Skip to content

Releases: spiffcs/hoard

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 27 Aug 22:16
d7f76ab

hoard v0.4.0

Important

Your database migrates on first launch, v33 → v36. It is backed up first,
beside itself as hoard.db.bak-v33-<date>. v36 rebuilds the cards table so
card characteristics are stored rather than recomputed from raw JSON on every
read: expect one slower launch and a larger file, and faster lists, sorts and
filters from then on. --json documents move to schema 1.2.0, which adds
paid to holdings rows.

Record what you paid

The add flow asks, per copy, and the URL form takes it on the command line:

hoard add https://scryfall.com/card/uma/7/ulamog-the-infinite-gyre --paid 12.50

Ebon Ante

--format aaa --era builds the Alpha-through-Alliances ante pool played as
Ebon Ante:
thirteen sets, and the five Apocalypse painlands.

hoard compendium --format aaa --era ebon-ante.db

A compendium is priced as it is built

The build records the day's prices as it goes and tells you so when it finishes. Tokens, emblems
and art cards are never seeded now.

Round-trip a ManaBox collection

hoard export --format manabox

hoard export --binder Binder --format manabox -o manabox.csv

Purchase price, condition and language survive going out and coming back in.
One fold to know about: ManaBox's excellent lands on near_mint on the way
in, because hoard carries five grades where ManaBox writes six.

In the browser

  • One penny filter. Movers, market and dips share a single penny filter
    rather than each keeping its own, and its line starts at $1.00 rather than
    $0.50.
  • Cost basis in the movers window, alongside the 7, 30 and 90 day lookbacks.
  • Dips and momentum load at startup with the rest of the price data, so
    opening the view no longer pauses to compute it.
  • Comps and rendered art are kept for the session, so coming back to a card
    does not fetch or redraw it again.

Faster

  • Card characteristics are stored rather than recomputed per row (schema v36),
    and set codes are indexed (v35). This is most of the compendium build and
    browse speedup, and the reason for the migration above.
  • Price trends read on their own connection, so a background price read no
    longer queues behind whatever the browser is doing.

Docs

  • Filtering — the
    filter language in one table, the same query / takes in the browser and
    hoard export --filter takes in a script.
  • Scripting
    --json, and splicing documents through a pipe to sweep what one filter
    cannot.
  • Recipes — a
    wantlist built out of an excluded binder.

Also changed

  • hoard add reads the language out of a Scryfall URL, so a /ja/ link adds
    the Japanese printing rather than the English one.
  • A card is completed as it is added, in the browser and in the add flow, rather
    than being left thin until the next backfill.

Fixed

  • Declining the confirm at the end of an add ends that card, not the session.
  • Page up and page down step by the height of the pane you are looking at rather
    than the other one's.

Install

curl -sSfL https://tools.aithirne.com/hoard/install.sh | sh -s -- -b "$HOME/.local/bin" v0.4.0

Or go install github.com/spiffcs/hoard/cmd/hoard@v0.4.0 (Go 1.26+).

Tip

New here? hoard demo opens the browser on a sample collection without
touching a database of yours.

Verifying this release

$ cosign verify-blob \
    --bundle checksums.txt.sigstore.json \
    --certificate-identity-regexp "^https://github.com/spiffcs/hoard/.*" \
    --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
    checksums.txt
Verified OK

Full changelog: v0.3.0...v0.4.0

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 25 Aug 22:37
v0.3.0
1d01959

hoard v0.3.0

Build a compendium for a format and price it, pipe a filtered export straight
into a move, and see a set's completion cost without leaving the browser.

Important

--format now keeps every printing of a legal card, reprints included.
Scryfall records legality per card rather than per printing. Reprints are
legal to play and are frequently the cheapest copy you can buy. If you want
the period-correct set list instead, use --era.

Formats know their own era

--era narrows a format to the sets it grew up in: the 29 sets from Fourth
Edition through Scourge for premodern, and everything released before
Commander 2011 for predh. A format with no era of its own refuses the flag
rather than quietly ignoring it.

hoard compendium build premodern.db --format premodern --era

Filter an export, pipe it into a move

hoard export --filter takes the browser's filter language, and hoard move
files a piped holdings document into a binder. Together they are a bulk move:

hoard export --binder Binder --json --filter 'price<1' | hoard move --to Bulk

In the browser

  • Finish a set. Price what completing a set would cost, and split a set into
    what you hold and what you still need. View uncollected under the set view by
    pressing b.
  • Streaks. The card detail names a run of rises or falls instead of leaving
    you to read it off the sparkline.
  • Vendor prices load in the background at startup, so the browser is usable
    immediately.
  • The collection pane stays put. The selected card previews below it rather
    than the sidebar scrolling away to make room for art.
  • Raw only. ToggleRawOnly in the command palette adds and removes
    finish:nonfoil, hiding every foil, etched and treated printing in one key.
  • A price refresh names the day its data is from.
  • Card art is drawn in proportion. hoard measures the terminal's cell aspect
    at startup instead of assuming a shape.

Docs

Adding cards now documents the TUI add flow and the iPhone scanner end to end.

Also changed

  • The add flow's confirm screen always names the binder a card is going into
  • The Go toolchain floor is pinned to 1.26.7, clearing four reachable
    standard-library advisories.
  • spf13/pflag 1.0.9 → 1.0.10, charmbracelet/x/ansi 0.11.7 → 0.11.8.

Fixed

  • The card detail refreshes when a set view resets. The printing's document is
    refetched and a thin price history backfilled, instead of the previous card's
    detail sitting there.
  • Deck list imports keep their sideboard rows.
  • Scryfall calls are paced across every endpoint together rather than per
    endpoint class alone, and a rate-limited request backs off for as long as
    Scryfall asks.
  • A sort tie in the browser breaks on the printing rather than only the name.

Install

curl -sSfL https://tools.aithirne.com/hoard/install.sh | sh -s -- -b "$HOME/.local/bin" v0.3.0

Or go install github.com/spiffcs/hoard/cmd/hoard@v0.3.0 (Go 1.26+).

Tip

New here? hoard demo opens the browser on a sample collection without
touching a database of yours.

Verifying this release

$ cosign verify-blob \
    --bundle checksums.txt.sigstore.json \
    --certificate-identity-regexp "^https://github.com/spiffcs/hoard/.*" \
    --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
    checksums.txt
Verified OK

Full changelog: v0.2.0...v0.3.0

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 24 Aug 00:39
v0.2.0
fca0542

hoard v0.2.0 Release Notes

Your database is upgraded from schema v30 to v33 on first launch. hoard backs up
the old file beside it before migrating.

Added Features

  • Dip & Momentum joins the view cycle (v): printings sitting at the floor of their recent range, and printings climbing without a down day [7df879b]
  • Deck folders: group decks one level deep, nested in the sidebar with copies and value rolled up; hoard folder new|list|rename|rm and hoard deck move [f8fc38c]
  • Fold a folder away with space: the sidebar remembers what you folded between launches [82475c5]
  • Move a deck into a folder with m: hoard will offer to create the folder if the name is new; :NewFolder creates an empty one [82475c5]
  • Leave a binder out of your totals with hoard binder exclude, or x in the browser [fee6d8a]
  • Select a run of rows with shift+↑ / shift+↓; the header reports copies, value and row count [fee6d8a]
  • Name a deck yourself with hoard deck rename or R [82475c5]
  • R renames binders, decks and folders, not just binders [82475c5]
  • Compendium generator builds a browsable database of printings you do not own, priced and backfilled: task compendium -- -rarity mythic,rare -since 2020 mythics-rare.db [08460b4]

Bug Fixes

  • Cycling views no longer loses the collection selected in the sidebar [f8fc38c]
  • The sidebar's VALUE column no longer shifts when folders fold and unfold [fca0542]
  • schema/sqlite/schema-latest.sql was emitted with truncated trigger bodies and is executable SQL again [f8fc38c]
  • MTGJSON's normal finish is translated to nonfoil where the payload is decoded, rather than in three places downstream [32c5077]
  • A TCGplayer low price below half the mid is no longer trusted as an ask; Direct is preferred where present [fee6d8a]

Additional Changes

  • Finishes are a compiler-checked type and constrained in the schema with CHECK, so an unknown finish cannot reach the database from any path [32c5077]
  • Compendium databases refuse every command that writes, so one cannot be edited by accident [08460b4]

Verifying this release

$ cosign verify-blob \
    --bundle checksums.txt.sigstore.json \
    --certificate-identity-regexp "^https://github.com/spiffcs/hoard/.*" \
    --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
    checksums.txt
Verified OK

macOS binaries are Developer ID signed and notarized.

(Full Changelog)

v0.1.1

Choose a tag to compare

@github-actions github-actions released this 13 Aug 06:35
v0.1.1
2cf4142

Changelog

Fixes

  • 2cf4142 fix(security): sanitise foreign strings and bound decompression

Other changes


Verification:

cosign verify-blob \
    --bundle checksums.txt.sigstore.json \
    --certificate-identity-regexp "^https://github.com/spiffcs/hoard/.*" \
    --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
    checksums.txt

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 13 Aug 05:06
v0.1.0
0c76759

Changelog

Features

  • e407e72 feat(browse): fold unpriced into a three-table watches screen
  • c12930a feat(browse): re-read on a neighbour's writes, and make r keep its place
  • d2923d5 feat(browse): scroll the detail overlay with the wheel
  • 02f498f feat(browse): the collection pane filters views
  • 57ab37e feat(deck): add --dry-run to deck add
  • d77488e feat(detail): bid history, spread-over-time, and per-card comps
  • 59c2b31 feat(export): add --format text so a deck can come home
  • f2541c3 feat(ios): let any tier be silent
  • f8d2f31 feat(json): binders, guessed, and the percentage movers already showed
  • 5c17301 feat(json): carry card facts, and set the schema baseline at 1.0.0
  • b1bb072 feat(market): the comp sheet as a fourth table
  • b35d7ac feat(prices): refuse a market price its own asks contradict
  • 4eee266 feat(scan): port the phone link into Go
  • 1eaeb58 feat(ui): WUBRG identity bubbles up from the data
  • 04f5b3e feat(ui): WUBRG identity palette; NO_COLOR
  • 6669598 feat(ui): card images on by default
  • 0a59396 feat(ui): identity treatment
  • ac139cf feat(ui): trim help to the command tables
  • e6e3ad5 feat(ui): vocabulary
  • 75a6c9d feat(watch): alert on a percentage move, anchored to a trailing high
  • 1e5bd68 feat(watch): read import from stdin, and allow a band on add
  • 4713c91 feat(watch): watch the printing you own, and make standing watches readable
  • 146d04d feat: --json documents with schema
  • 4d2c086 feat: MARKET palette and container filters
  • 3ce76ed feat: TCGplayer CSV ingest for price history
  • fbca0d5 feat: TLS with TOFU pinning for the scan link
  • 5ee672c feat: add-flow command palette
  • 6d6a136 feat: add-flow destination picker
  • 6fade8b feat: add-session exit and pending scan queue (#9)
  • 2ff7ed5 feat: all-cards list, guarded add exits, palette
  • 891c823 feat: anchor the marker search on the copyright
  • 85116cf feat: arbitrage command surfacing vendor prices
  • dee48e6 feat: art index with pHash and a footprint cache
  • 4fc5215 feat: browse by set, held-row editing
  • 52d1ab2 feat: browse interop help and operation state
  • 1c7c7dc feat: bulk paste entry — add --file, stdin, and --binder
  • 62803e3 feat: bulk watch list import
  • 0c4ba93 feat: buylist view as an inverted market table
  • 86d4687 feat: card detail pane and browse view polish
  • 1aa49ae feat: card image aspect and detail layout
  • 5eb1e38 feat: carry a condition through import and export
  • c1970a4 feat: chime per processed card; view-ranked palette
  • c2864c3 feat: command palette and a single registry for browser actions
  • ee0fa85 feat: deck containers and bulk import
  • bf481fc feat: edit a holding's condition
  • bf707aa feat: edit and delete cards from the set view
  • 615b161 feat: embed the add cascade
  • 3d57a17 feat: etched gets its own price
  • 574bac5 feat: gradient theming for movers and comps
  • 89bb6d0 feat: handheld scan view driven from the phone
  • b40e59a feat: hands-free scanning
  • b45582b feat: held-row editing and market table trims
  • 61d225a feat: hoard export (canonical CSV, Moxfield, Archidekt)
  • 53b803c feat: hoard import (ManaBox, Moxfield, Delver Lens, hoard CSV)
  • 3877745 feat: hoard list sorting; mtgjson storage design doc
  • d9b26b1 feat: hoard report; dated valuation formats
  • 5884b35 feat: hoard watch — price alerts that fire
  • 912d3d8 feat: iPhone capture app with CardKit, ScanLink, and ScanWire
  • 1eea727 feat: import ledger and a round-trippable CSV
  • 47dde52 feat: in-TUI add, interop, and operation confirmations
  • 470b154 feat: initial CLI for cataloging a collection
  • 379c5b7 feat: know a new card from a second look at the old one
  • cb8817c feat: land summary impact coloring
  • 59ea0d4 feat: let the capture receipt scroll back through the session
  • d45fa7e feat: list the collection one row per finish
  • 4b7b987 feat: long-running operations run inside the tui
  • f640c13 feat: market comps in browse
  • 30d2f27 feat: market settings and TCG price plumbing
  • 9eadabf feat: market table sorting and browse row editing
  • 8fec3e9 feat: merge command (#10)
  • 4aff813 feat: movers report from price history
  • 8779bed feat: multi-card scanning
  • 692ecd2 feat: multiple named binders
  • aaf8d03 feat: old-frame title/number arbitration; new scan fixtures
  • e30f141 feat: open card detail from unpriced
  • bcdaefa feat: pHash art index
  • 24f8be7 feat: palette curation, gradients, pane updates
  • d04db35 feat: per-finish foil pricing
  • dcb7832 feat: per-tier scan sounds and a settings screen
  • 634f93d feat: persistent add mode and per-user db location
  • 5837947 feat: price fallbacks, schema migrations, and collector-number scanning
  • 397ec18 feat: price history schema migration
  • 95f1753 feat: printings, pricing, and browse fixes from a feedback session
  • 1c0439e feat: progress contract, CLI renderer, and graceful interrupts
  • d935e57 feat: raise the capture ceiling to 1920x1440, pin Vision's revision
  • 55da04d feat: read old-frame white borders
  • f9b554d feat: read pre-collector-number frames
  • d379a88 feat: read the old-frame foil marker
  • 4f3d03a feat: read the printed language
  • 9a1282b feat: renameable default binder
  • 1fcf893 feat: risers and sinkers in collection
  • de5efa8 feat: scan cards with an iPhone camera
  • 32ea50b feat: scanner trigger tuning and a rules-quote title fixture
  • feec096 feat: scene signature and trigger tuning for the phone
  • c895933 feat: search TUI
  • ce914b2 feat: sparkle foil detection and schema v24
  • 078db6f feat: trim the CLI surface and polish the scanner
  • 278b330 feat: two-pane browser TUI and a local Scryfall card catalog
  • 03f2e92 feat: ui table and formatting layer behind summary
  • 8e647de feat: update the all-cards list; first-run catalog
  • 5bc2fd2 feat: value snapshots and a hoard-value sparkline
  • 8176927 feat: watch-this-card everywhere
  • b7fcc4b feat: watches view, fired banner

Fixes

  • 178df10 fix(browse): make / filter the market view
  • 65788cf fix(browse): make / filter the movers view
  • 2d83f53 fix(browse): report the deck lines the browser could not read
  • fe56903 fix(browse): report the losses update-prices and backfill were hiding
  • 1117d90 fix(ci): stop pinning oras in the shared toolchain
  • 892e16a fix(cli): keep help inside a narrow terminal
  • e84ac14 fix(cli): refuse a repeated export scope, and an unknown import format
  • 527b061 fix(cli): show global flags in help, and ship the schema
  • 29fd302 fix(cli): stop deck restores from looking clean when lines were skipped
  • d82961c fix(decksource): read Archidekt and Deckstats text exports as exported
  • 5fd41c1 fix(import): check the binder before resolving
  • a06c562 fix(import): refuse a CSV row longer than its header
  • 8cbe12e fix(install): anchor the checksum lookup to the whole filename
  • 887cf4b fix(ios): drop the pairing code from the waiting status
  • ad04f0d fix(ios): keep advertising when a session ends
  • ff5a62d fix(ios): read the team identifier from the certificate OU
  • 1b2bb4f fix(ios): restart the listener when the advertisement dies
  • 80eb760 fix(json): stop reporting colorless cards as -
  • 3855cc8 fix(json): stop three types claiming a card's colour is unknown
  • eb92db6 fix(market): stop inventing an etched sheet for printings without one
  • 16c7fba fix(movers): a window is a range, not a precondition
  • d9a0123 fix(scan): delete the pairing guess, route on the sentinel instead
  • 90e78cd fix(scan): keep a phone-offered second-copy slot past the next card
  • e77f96c fix(scan): keep the error sentinel that friendly() was throwing away
  • 6639e9f fix(scan): pin the collector-block rescue at compile time
  • ad32ac4 fix(store): repair two comments gofmt had corrupted, and guard the rest
  • 534d581 fix(ui): agree the count
  • 9b0d25d fix: All Cards view and help text
  • 2957934 fix: MARKET consistency + holdings cursor; lock in scanner HUD sounds
  • b2301ea fix: a stalled MTGJSON download fails
  • 998cf1d fix: allow bottom location to be read
  • 04791ad fix: browse status line text
  • e242a2a fix: clear the pre-launch audit red list
  • 545e60b fix: container filtering and holdings counts in browse
  • b0a4519 fix: count a sliver growing back into the whole card as stillness
  • 383c34d fix: filters on MARKET view
  • 07ee8a9 fix: name the cards pane when the collection is empty
  • 7c4c681 fix: network edge resilience and clear output
  • d4cce89 fix: only comp vendor prices we can tie to the held product
  • cf80b40 fix: pin the card signature's sampling window to the shutter's geometry
  • e1e44ec fix: price aggregation blips
  • 2009ef1 fix: reject flavor-text attributions
  • d82750f fix: release fix syft
  • 4b7ecb2 fix: say what movers counted, and let the guess queue reach zero
  • 43ff841 fix: scan drain race, cache fallback, quote order; dedupe shared rules
  • e7b0fa0 fix: scanner HUD and capture presentation
  • a393ba4 fix: scanner drops lingering re-sightings
  • 4296be9 fix: sort every browse view by its own columns, S reverses
  • f0d695b fix: stacked-card trigger and wire framing
  • 4280a02 fix: store forward-compat, backup ordering, atomic import writes
  • 08e36fe fix: tie opportunity rows to the held product
  • feb2e5d fix: update make and Taskfile

Other changes

  • 432d81c build(scan): publish fixture frames to ghcr, pinned by digest
  • 53ce775 build: binny, Taskfile, goreleaser, and install.sh
  • 6ee1c4b chore(deps): Bump github.com/santhosh-tekuri/jsonschema/v6
  • 5fdf5cd chore(deps): update Go modules and GitHub Actions
  • 700b8de ci: codeql, lint, and release workflow fixes
  • 446b5be ci: disable macOS scan workflow until runner budget allows
  • 49a23ac ci: fix the main workflows
  • a96b38a ci: rename the default branch to main
  • 00a2c3c ci: scan fixtures path-filtered macOS workflow
  • b9a0e7b ci: workflows
  • fc43c39 demo: demo and docs
  • 2175647 perf(scan): end discovery at the answer, not the deadline
  • 91084d7 perf: serve same-day arbitrage quotes from a filtered day-cache
  • 2cd6192 refactor!: rename arbitrage to market
  • d85f4bb refactor!: rename finish 'normal' to 'nonfoil'
  • e55bfee refactor(catalog): drop the image_uri column
  • ca584c7 r...
Read more