{"id":28092427,"url":"https://github.com/mrusme/kopi","last_synced_at":"2025-05-13T13:14:30.635Z","repository":{"id":288438030,"uuid":"836914227","full_name":"mrusme/kopi","owner":"mrusme","description":"Command-line (CLI) coffee journal designed for coffee enthusiasts.","archived":false,"fork":false,"pushed_at":"2025-04-17T14:01:53.000Z","size":1146,"stargazers_count":7,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-13T13:14:23.321Z","etag":null,"topics":["aeropress","brewing","cli","coffee","command-line","command-line-tool","espresso","habit-tracking","journal","mocha","tracker","tui"],"latest_commit_sha":null,"homepage":"https://xn--gckvb8fzb.com/kopi-track-your-coffee-brewing-consumption/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrusme.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"custom":["https://github.com/mrusme#support"]}},"created_at":"2024-08-01T20:28:51.000Z","updated_at":"2025-04-28T04:58:42.000Z","dependencies_parsed_at":"2025-04-18T04:50:32.066Z","dependency_job_id":"6455c07f-d983-4983-b0d4-9967fe25e55c","html_url":"https://github.com/mrusme/kopi","commit_stats":null,"previous_names":["mrusme/kopi"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrusme%2Fkopi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrusme%2Fkopi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrusme%2Fkopi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrusme%2Fkopi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrusme","download_url":"https://codeload.github.com/mrusme/kopi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253948503,"owners_count":21988961,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aeropress","brewing","cli","coffee","command-line","command-line-tool","espresso","habit-tracking","journal","mocha","tracker","tui"],"created_at":"2025-05-13T13:14:30.113Z","updated_at":"2025-05-13T13:14:30.624Z","avatar_url":"https://github.com/mrusme.png","language":"Go","funding_links":["https://github.com/mrusme#support"],"categories":[],"sub_categories":[],"readme":"# Kopi\n\n![Kopi](.README.md/cover.jpg)\n\n\u003e From Malay _kopi_ (“coffee”) and Hokkien 咖啡 (ko-pi); the latter is also\n\u003e derived from the former.\\\n\u003e -- [Wiktionary](https://en.wiktionary.org/wiki/kopi)\n\n_Kopi_ is a command-line (CLI) coffee journal (or _habit tracker_), designed for\ncoffee enthusiasts. It lets you track coffee beans, equipment usage, brewing\nmethods, and individual cups.\n\nThe tracked data offers insights into bean and roast preferences, caffeine and\ndairy consumption, and equipment usage patterns. This helps users refine their\ncoffee choices while managing caffeine intake for a more enjoyable and\nresponsible experience.\n\n_Kopi_ focuses on meticulously tracking every step of the coffee preparation\nprocess. Unlike standard coffee or caffeine tracking apps, it requires more\ndetailed input to function effectively. If you only want to track the cups of\ncoffee you drink without monitoring the beans/roasts and the preparation methods\nused, _Kopi_ may not be the best fit for you. Think of _Kopi_ as a coffee\njournal that lets you rate individual roasts and analyze how different roasts,\nbrewing methods, and drink types influence your preferences.\n\n_Kopi_ stores everything **locally** and does not send any data to third-party\nservices unless explicitly mentioned before an operation (e.g. requesting\ncurrent exchange rates from the ECB, for price input/conversions of individual\ncoffee bags). _Kopi_ does not employ analytics libraries/services.\n\n## Status\n\n_Kopi_ is still in its early stages. Some features might not be working as\nexpected and others might very well be missing. If you **depend** on your coffee\njournal, do not use _Kopi_ at this stage, as things might change and, in the\nworst case, randomly break. If you're feeling adventurous or you're looking to\ncontribute to the project, please find all the relevant information down below.\n\n### To do\n\n- [ ] Update/edit ...\n  - [ ] equipment\n  - [ ] coffee\n  - [ ] bag\n  - [ ] cup\n- [ ] Decommission equipment\n- [ ] Close bag\n  - [ ] Ask to close bag when finished (based on consumed cups)\n- [ ] (TODO)\n\n## Install\n\n### From Release\n\nDownload the [latest release](https://github.com/mrusme/kopi/releases/latest)\nand unpack it:\n\n```sh\n▲ tar -xzf ./kopi_*.tar.gz\n```\n\nThe binary `kopi` can be moved wherever you please.\n\n### From Source\n\nClone this repository\n\n- from [GitHub](https://github.com/mrusme/kopi)\n  ```sh\n  $ git clone git@github.com:mrusme/kopi.git\n  ```\n\nThen cd into the cloned directory and run:\n\n```sh\n$ make\n```\n\nThe binary will be available at `./build/kopi` and can be moved wherever you\nplease.\n\n## Use\n\n_Kopi_ follows a structured three-step workflow for tracking coffee consumption,\nessential for its functionality and insights. The first step is typically done\nonce — during setup or when equipment changes. The second step is performed\nregularly, while the third step, tracking actual consumption, is done for every\ncup.\n\n### Steps\n\n#### Step 1: Add equipment\n\nCoffee equipment is the first piece of information that _Kopi_ requires. Most\ncoffee enthusiasts will usually have at least two pieces of coffee equipment at\ntheir disposal:\n\n- A coffee grinder\n- A coffee maker\n\nThis equipment needs to be added to _Kopi_ before tracking coffee brewing and\nconsumption. To do so, the following command is used:\n\n```sh\n▲ kopi equipment add\n```\n\n![`kopi equipment add`](.README.md/kopi_equipment_add.gif)\n\nThe command will guide the user through the adding process. It is also possible\nto provide all required fields as flags to the command. For more information on\nhow to do so, check the output of `kopi equipment add --help`.\n\n**Note:** If you don’t have coffee brewing equipment and typically get your\ncoffee from a barista, add their brewing method as a _dummy_ entry. For\nespresso-based drinks, add an _espresso maker_; for pour-overs or AeroPress, add\na _coffee maker_. However, keep in mind that _Kopi_ is **not** designed for\ntracking individual cups from various coffee shops—there are better tools for\nthat. Instead, _Kopi_ is aimed at coffee enthusiasts who want to document their\ncoffee experiences, ideally using their brewing methods.\n\n#### Step 2: Open a bag of coffee\n\nCoffee bags are the second key element in tracking brewing and consumption.\nEvery cup requires a designated bag of coffee. Previously _opened_ bags can be\nused until their beans are depleted, at which point a new bag must be _opened_.\nMultiple bags can be _open_ at the same time, but only one can be selected per\ncup. For blends, a dedicated bag must be prepared and then _opened_.\n\nTo _open_ a new bag of coffee the following command is used:\n\n```sh\n▲ kopi bag open\n```\n\n![`kopi bag open`](.README.md/kopi_bag_open.gif)\n\nThe command will guide the user through the opening process. It is also possible\nto provide all required fields as flags to the command. For more information on\nhow to do so, check the output of `kopi bag open --help`.\n\nTo list all **open** bags, the following command can be used:\n\n```sh\n▲ kopi bags list\n```\n\nThe command accepts the `--all` parameter to list all bags, instead of only the\nopen ones.\n\n_Note:_ `bags` is an alias of the `bag` command that helps with making the\ncommand read more naturally. The command `kopi bag list` works and can also be\nused.\n\n#### Step 3: Drink a cup of coffee\n\nTo track a cup of coffee, the following command is used:\n\n```sh\n▲ kopi cup drink\n```\n\n![`kopi cup drink`](.README.md/kopi_cup_drink.gif)\n\nThe command will guide the user through the tracking process. It is also\npossible to provide all required fields as flags to the command. For more\ninformation on how to do so, check the output of `kopi cup drink --help`.\n\n## Insights\n\nA wide range of insights can be extracted from the data that has been tracked\nover time. The `kopi insights` command aggregates the information and displays\nit. It supports multiple output formats and custom periods. For more information\ncheck the output of `kopi insights --help`.\n\n![`kopi insights`](.README.md/kopi_insights.png)\n\n### Ranking\n\nThe database calculates an overall ranking for each coffee based on ratings from\nindividually tracked cups. Use the `kopi coffee ranking` command to view the\nranking:\n\n![`kopi coffee ranking`](.README.md/kopi_coffee_ranking.png)\n\n_(ltr: Rank, coffee name, roaster, score calculated from individually rated\ncups)_\n\n### _\"Mobile App\"_\n\n_Kopi_ does not have a mobile app to track coffee consumption. Instead, _Kopi_\nis using a new approach to tackle this need: **Pen and paper**.\n\nWith _Kopi_ it is possible to track cups of coffee using a simple notebook, by\nwriting down consumed cups in a structured format:\n\n![Notebook example](helpers/ocr/sample.jpg)\n\n_Kopi_ uses an [Ollama](https://github.com/ollama/ollama) backend to _read_\nphotos of such notes using `llama3.2-vision` and extract all the information\nnecessary to automatically import these entries into its database.\n\nFor more information on this approach,\n[head over to this post](https://xn--gckvb8fzb.com/kopi-track-your-coffee-brewing-consumption/#mobile-app?utm_source=README).\n\n#### Ollama\n\nThe Ollama service can either be run locally (on a powerful enough machine) or\nremotely. On an AMD Ryzen 9 5950X CPU (no GPU) extracting data from such a photo\nusually takes around a minute. On an AMD Ryzen 7 5800U (no GPU), however, it's\nalmost always 20x slower. Given a\n[supported GPU](https://github.com/ollama/ollama/blob/main/docs/gpu.md) these\nnumbers change drastically.\n\n## Development\n\n_Kopi_ is written in Go and uses\n[mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) to store all its data.\nBecause of this, building _Kopi_ requires `gcc` to be available and\n`CGO_ENABLED=1` to be set.\n\nWhether you're a developer looking to contribute, or you're interested in\nunderstanding the inner workings of the project, this section will guide you\nthrough the development setup, the architecture of the code, and how you can get\ninvolved. If you plan to contribute or make modifications, feel free to follow\nalong and dive into the Go codebase to help improve this tool!\n\n### CGO\n\nBefore building _Kopi_, make sure that CGO is enabled inside your Go\nenvironment:\n\n```sh\ngo env | grep CGO_ENABLED\n```\n\nIf CGO is not enabled (`0`) try manually enabling it:\n\n```sh\ngo env -w CGO_ENABLED=1\n```\n\nIf this command fails with something along the lines of\n`cgo: C compiler \"gcc\" not found: exec: \"gcc\": executable file not found` your\nGo installation cannot seem to find the `gcc` compiler. Make sure you have `gcc`\ninstalled and available in your `$PATH`.\n\n### Build\n\n_Kopi_ can be built using the standard `go build` command, although it is\npreferable to use `make build` (or simply `make`).\n\n### Implementation\n\nThe following section gives an overview of how the application is built and how\nits features are implemented, providing an in-depth look at the decisions and\nstructure behind the code.\n\n#### Database \u0026 database access\n\n_Kopi_ uses Sqlite3 to store all its data locally. The database structure and\nseed data are available within the [migrations](migrations/) folder and are\nbeing _baked_ into the binary using Go's EmbedFS.\n\nThe Go code is built around a minimal _Database Abstraction Layer_ (_DAL_), as\nwell as individual _entities_ (`Bag`, `Coffee`, `Cup`, etc.) that have _models_\nthat are built upon _generic Data Access Objects_ (_DAOs_). This data\narchitecture uses _generics_ to reduce the required boilerplate and keep the\nimplementation as lightweight and _DRY_ as possible. The concept was documented\nby James Kirk in [this repository](https://github.com/Jimeux/go-generic-dao) and\ncontains a write-up with the implementation details.\n\n#### Coffee and caffeine\n\n_Kopi_ makes some assumptions about coffee and its caffeine content. It uses a\nformula to approximate the caffeine content in a coffee drink based on the\namount of ground coffee, brewing method, and roast level:\n\n```math\nC = G \\times E_m \\times R \\times (1 - L_m)\n```\n\nWhere:\n\n- $\\( C \\)$ = estimated caffeine content in milligrams (mg)\n- $\\( G \\)$ = mass of ground coffee used (grams)\n- $\\( E_m \\)$ = base extraction yield (mg of caffeine per gram of coffee,\n  dependent on brewing method)\n- $\\( R \\)$ = roast level adjustment factor\n- $\\( L_m \\)$ = loss factor due to filtration, retention, or degradation\n  (fractional value, dependent on brewing method)\n\nThe following values for $\\( E_m \\)$ (Base Extraction Yield by Brewing Method)\nare assumed:\n\n| Brewing Method                               | Base Extraction Yield $\\(E_m\\)$ (mg/g) |\n| -------------------------------------------- | -------------------------------------- |\n| **Espresso**                                 | 8-12 mg/g                              |\n| **Drip Coffee (Filter, Pour-over, Machine)** | 6-10 mg/g                              |\n| **French Press (Immersion Brewing)**         | 6-9 mg/g                               |\n| **AeroPress**                                | 7-10 mg/g                              |\n| **Cold Brew**                                | 5-8 mg/g                               |\n| **Turkish Coffee (Cezve)**                   | 10-13 mg/g                             |\n| **Moka Pot**                                 | 8-12 mg/g                              |\n\nThe following values for $\\( L_m \\)$ (Loss Factor by Brewing Method) are\nassumed:\n\n| Brewing Method                               | Approximate Loss Factor $\\(L_m\\)$ |\n| -------------------------------------------- | --------------------------------- |\n| **Espresso**                                 | 0.05                              |\n| **Drip Coffee (Filter, Pour-over, Machine)** | 0.10                              |\n| **French Press (Immersion Brewing)**         | 0.05                              |\n| **AeroPress**                                | 0.10                              |\n| **Cold Brew**                                | 0.15                              |\n| **Turkish Coffee (Cezve)**                   | 0.05                              |\n| **Moka Pot**                                 | 0.08                              |\n\nThe following values for $\\( R \\)$ (Roast Level Adjustment Factor) are assumed:\n\n| Roast Level      | Adjustment Factor $\\(R\\)$ |\n| ---------------- | ------------------------- |\n| **Light Roast**  | 0.95                      |\n| **Medium Roast** | 1.00                      |\n| **Dark Roast**   | 1.10                      |\n\nFurther, the following assumptions are made:\n\n- Light roasts have a slightly lower extraction efficiency $\\(R = 0.95\\)$.\n- Medium roasts serve as the baseline $\\(R = 1.00\\)$.\n- Dark roasts extract more caffeine per gram due to their porous structure $\\(R\n  = 1.10\\)$.\n\nThe _Approximate Extraction Yields_ $\\(E_m\\)$, as well as the _Approximate Loss\nFactors_ $\\(L_m\\)$ for different brewing methods, are stored within each\n[method's database entry](migrations/006_methods.up.sql).\n\n#### Example\n\nFor a _drip coffee_ using 20g of lightly roasted $\\(R\\)$ ground coffee $\\(G\\)$,\nan extraction yield of (on average) 8mg $\\(E_m\\)$, and a loss factor $\\(L_m\\)$\nof 0.10, the calculation looks as follows:\n\n```math\n\\begin{align}\nC = 20 \\times 8 \\times 0.95 \\times (1 - 0.10) \\\\\n\nC = 20 \\times 8 \\times 0.95 \\times 0.90 \\\\\n\nC = 136.8 \\text{ mg}\n\\end{align}\n```\n\nA cup would hence contain roughly 137 mg of caffeine.\n\n#### Currency\n\n_Kopi_ allows users to enter prices for the coffee that they add to the\ndatabase. _Kopi_ stores all prices in USD, rather than in the currency of the\nuser. This allows for easier price comparisons at a later stage. To support\ndifferent currencies and convert them into USD the tool uses a conversion\ndocument published by the European Central Bank:\n\n```\nhttps://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml\n```\n\nIf the user adds a price to a coffee bag, they will be prompted with whether\nthey would like to query the service to retrieve up-to-date currency conversion\ninformation.\n\nThere is an ongoing effort of dedollarisation by also storing the price in\n1/100000000 of a Bitcoin (Satoshis, or _Sats_) for use as a base currency at a\nlater stage.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrusme%2Fkopi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrusme%2Fkopi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrusme%2Fkopi/lists"}