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.