colorful rat Ratfactor.com > Dave's Repos

addrbook

A CLI contact management program
git clone http://ratfactor.com/repos/addrbook/addrbook.git

addrbook/README.md

Download raw file: README.md

1 # Addrbook - a contact management program 2 3 Manage your contacts with your favorite terminal text editor! 4 5 Less than 300 lines of Ruby. Written by hand by a human. 6 7 Addrbook was created to work with the Aerc email client, but is completely 8 useable from the command line and might also work within other email clients so 9 long as they can launch terminal applications. 10 11 If you want to jump right in and start using it, head down to the 12 'Configuration' section. 13 14 ## Text files _and_ a database? 15 16 Relational databases are great and text files are great. So which did I choose 17 for Addrbook? Both! I chose a database (SQLite) to store the address book 18 entries as proper relation database. But I also chose to interact with the 19 entries as text files. This gives us the best of both worlds! 20 21 When you view an entry, you are looking at a text file, but the data came from 22 the database. 23 24 You edit an entry by editing the text file in your favorite text editor. Then 25 Addrbook imports your changes back into the database. 26 27 (----------) +----------+ 28 ( ) | | 29 ( DB ) <----> | .txt | 30 ( ) | / 31 (----------) +---------/ 32 33 ^ ^ 34 Stored here Edited here 35 36 If you didn't know better, you wouldn't even know the database existed. But it 37 does and Addrbook won't work without it. 38 39 The "help" message that is printed when you run Addrbook with no arguments 40 explains how editing works in the form of a list: 41 42 1. Writes the database contents of the entry to a text file. 43 2. Opens the text file in your editor. 44 3. Imports the edited contact information back to the database. 45 46 After using this program daily for a couple months now, I am convinced that the 47 database + text file method not only works reliably, but is super flexible. You 48 get plain text input and output in the Unix fashion, while retaining the full 49 power and reliability of a proper industrial-grade database (SQLite). 50 51 ## Backing up your contact data 52 53 One of the problems with storing information in a binary format (even a very 54 good one like SQLite) is that it's hard to track it with standard source 55 control tools. 56 57 When you use Addrbook, the text files are retained after they have been used, 58 which means that the database and text files are always 100% in sync with each 59 other. 60 61 (The only reason this would not be true is if there was an error in Addrbook or 62 your computer crashed while you were editing an entry. Or you tricked it, but 63 that's on you.) 64 65 Therefore, it is completely reasonable to put the `txt` directory 66 under standard textual version control to keep track of changes 67 to your contact data. 68 69 Version control plus a standard automated backup system (you do have 70 a backup system, right?) should be quite good protection against 71 mistakes and equipment failures. 72 73 ## Configuration 74 75 First, to run `addrbook` at all, you'll need to install the `sqlite3` gem: 76 77 gem install sqlite3 78 79 There is no installer for Addrbook itself, so you'll need to prepare the 80 directories and database by hand (I made this tool for myself and I don't 81 need an installer): 82 83 mkdir ~/beans/addrbook 84 mkdir ~/beans/addrbook/txt 85 86 Create the `addrbook.db` database from the `make_db.sql` schema file. I like to 87 do this interactively in the sqlite3 shell to confirm everything is correct. 88 89 Example SQLite session (silently creates the required tables): 90 91 $ sqlite3 ~/beans/addrbook/addrbook.db 92 SQLite version 3.50.4 2025-07-30 19:33:53 93 sqlite> .read addrbook-repo/make_db.sql 94 95 While you're in there, verify the schema: 96 97 sqlite> .schema 98 CREATE TABLE contact ( 99 contact_id INTEGER PRIMARY KEY, 100 name, 101 added, 102 notes 103 ); 104 CREATE TABLE email ( contact_id INTEGER, email); 105 CREATE TABLE phone ( contact_id INTEGER, phone); 106 CREATE TABLE url ( contact_id INTEGER, url); 107 sqlite> .quit 108 109 Specify the path to the base directory in an environment variable like so: 110 111 ADDRBOOK_PATH=$HOME/beans/addrbook 112 export ADDRBOOK_PATH 113 114 _Or_ you can hard-code your own path in the addrbook source like I did! 115 (See the source, near the top.) 116 117 Note: You can test addrbook with a temporary path like I often did 118 while developing, like so: 119 120 $ ADDRBOOK_PATH=/tmp/addr_test/ ./addrbook list 121 122 In summary, the address book directory should contain the following structure: 123 124 [dir]/addrbook.db - sqlite3 database, init with make_db.sql 125 [dir]/txt/ - empty directory, will store text files 126 127 The editor used to edit contacts is determined in the following order: 128 129 * Environment variable `$VISUAL` 130 * Or evironment variable `$EDITOR` 131 * Or Vim 132 133 A viewer is determined likewise: 134 135 * Environment variable `$PAGER` 136 * Or less 137 138 The 'cat' command is hard-coded to run whatever executable is named 'cat' 139 on your system. 140 141 ## Aerc quickstart 142 143 I wrote Addrbook for use within the Aerc terminal email client. 144 145 I've got this in `~/.config/aerc/binds.conf`: 146 147 [view] 148 # Address Book: av,ae,aa = "Address View, Edit, Add" 149 av = :term addrbook view '{{(index .From 0).Address}}' '{{(index .From 0).Name}}'<Enter> 150 ae = :term addrbook edit '{{(index .From 0).Address}}' '{{(index .From 0).Name}}'<Enter> 151 aa = :term addrbook add '{{(index .From 0).Address}}' '{{(index .From 0).Name}}'<Enter> 152 153 (You can also add the same set of commands to the main `[messages]` list view, 154 but you'll need to change or remove the existing 'a' shortcut for archiving.) 155 156 For a full explanation of these bindings, see the "Aerc binding details" 157 section below. 158 159 ## General usage 160 161 When you run addrbook without any arguments, it prints a usage summary which 162 will always be current. (I'll try to keep it current here too, but it's easy 163 to forget.) 164 165 Usage: addrbook <command> [params] 166 167 Available commands: 168 add [email addr] [name] Create new contact entry 169 edit <email addr | ID> Update contact as text, import changes. 170 view <email addr | ID> Display contact as text with pager 171 cat <email addr | ID> Output contact as text (to 'cat') 172 reimport <contact number> Updates contact DB entry from text. 173 list Display list of current contacts. 174 autocomplete-email <fuzzy> TODO 175 176 The 'edit' command is the normal way to update a contact. It: 177 178 1. Writes the database contents of the entry to a text file. 179 2. Opens the text file in your editor. 180 3. Imports the edited contact information back to the database. 181 182 The 'reimport' command performs only Step 3 and exists mostly for 183 recovery if the edit process was interrupted. 184 185 The three steps listed above are the most concise explanation I've managed to 186 write explaining how the edit process makes a round-trip from the database to 187 text files and back again. 188 189 ## Aerc binding details 190 191 Here's an explanation of the Aerc quickstart configuration above so you'll be 192 armed with the ability to modify mine or make your own shortcut bindings. 193 194 To quote `man aerc`: 195 196 To execute a command, press : to bring up the command 197 interface. Commands may also be bound to keys, see 198 aerc-binds(5) for details. 199 [...] 200 Dynamic arguments are expanded following aerc-templates(7) 201 depending on the context. 202 203 Creating new contacts in the address book from an email client will require 204 just the email address. Optionally, it can take the contact's name as well. 205 206 To test the value of an Aerc 'template' with a message selected in various Aerc 207 contexts (list, compose, view, etc.), you can use the built-in Aerc `echo` 208 command: 209 210 :echo {{.From}} 211 212 This was news to me until I started reading RFCs on my first attempt at this, 213 but an email's "From:" header can contain more than one sender for some dang 214 reason. So the `From` property actually returns a list. 215 216 To get the first email address and name to addrbook, I'm using the following 217 pair of templates as parameters. You can try these out with `echo`: 218 219 :echo {{(index .From 0).Address}} 220 :echo {{(index .From 0).Name}} 221 222 To open a new terminal emulator in a "tab" in Aerc, use the `term` command: 223 224 :term <cmd> [<arguments>] 225 226 (You can also leave off the command and Aerc will run your shell instead.) 227 228 When the command exits, the terminal will close. 229 230 The bindings config file is broken into sections. I've added mine to the 231 `[view]` section, which is when you're looking at an email, but not 232 composing a reply. Be careful about using a binding that starts with the 233 letter 'a' in the list context because that's bound by default to the 234 "archive" action! 235 236 As you can see in my 'aa' and 'ae' key binding examples, I put quotes 237 around the arguments as they're passed to addrbook. Not strictly needed 238 for the email address (which shouldn't have spaces!), but definitely 239 needed to pass a name with spaces like "John Smith" as a single argument. 240 241 242 243 ## Inspiration 244 245 This was initially inspired by Max Schillinger's 246 [emailbook](https://sr.ht/~maxgyver83/emailbook/). 247 It's less than 150 lines of commented shell script (and nearly half are for 248 handling the command-line interface). 249 250 I'd intended to re-implement emailbook in Ruby (so it would run on OpenBSD). 251 After I made some good headway on my clone (and had added a 'notes' field), I 252 was reading the Aerc man pages and realized there was another way to send the 253 the current contact's email address to the application from Aerc while leaving 254 STDIN available for interactive use. 255 256 So at this point, Addrbook bears zero resemblance to emailbook. Nevertheless, 257 without the inspiration, I never would have thought to make this at all. So 258 thanks Max! 259 260 Lastly, I wouldn't have explored this concept at all if I hadn't read 261 Derek Sivers's 262 [Why you need a database](https://sive.rs/dbt), which convinced me that I 263 should be keeping better track of my email friends!. 264 265 ## License 266 267 I still believe in the original mission of libre software. I honestly 268 don't know how I should be licensing things in 2026. If pressed, probably 269 a GNU license.