Not found.

How to display current virtualenv in your ZSH Prezto theme

It’s been a few years since I switched from Bash to ZSH on my personal laptop, and I’ve never regretted it. Out of the box, ZSH isn’t that great, but after customizing it using Prezto it’s an amazing timesaver in a lot of little ways.

Oh-My-ZSH is the most well-known ZSH customization framework, but it’s gotten pretty bloated over the years with 200+ plugins, 140+ themes, etc. With that many plugins, some of them are bound to conflict from time to time, and keeping everything straight can be a bit of a mess. It’s also not uncommon for OMZ users who enable a lot of plugins to report shell startup times >3 seconds, which is annoying.

Prezto started as a fork of Oh-My-ZSH focused on improving performance, and now is an entirely separate project. The Prezto maintainer is a bit gruff and much more inclined to say ‘no’ than ‘yes’ to pull requests, but I see this as a benefit because it minimizes bloat. 95% of the modules that I wanted were already built-in, and it was easy enough to fork the project to add a custom module for the Atom text editor.

Prezto is well-documented, as each module/plugin has its own Readme. Plus there are plenty of blog posts around discussing how to get started with Prezto. Personally, I found it best to just read the Readme for each module, decide which ones I wanted, and enable them. I use Gnu Stow to symlink the .zshrc , .zlogin , and .zpreztorc  to my ~/.dotfiles/zsh/  folder and manage them as part of my dotfiles repo.

You can see screenshots of all the default Prezto themes here: http://mikebuss.com/2014/04/07/customizing-prezto/

I prefer the Sorin theme, as it strikes a good balance of displaying enough information to be useful without showing so much that its distracting. For example, the prompt displays the path, but rather than showing the full path, it only displays the first character of the parent folders, which saves space, focuses the eye on the path name of the current folder, but also doesn’t leave you wondering whether you’re in first_app/requirements/ or second_app/requirements/. Behind the scenes, there are some nice touches such as retrieving Git information asynchronously in the background so it doesn’t slow down the display of the command prompt.

However, the one thing I perpetually missed in the Sorin theme was the active virtualenv – I was always typing which python . So this afternoon I finally sat down and figured out how to customize the theme to display it.

Now, whenever I activate a virtualenv, my prompt changes to:

(virtualenv_name) default/sorin/prompt/ >>>

and it just disappears if there’s no activated virtulaenv.

It’s quite easy if you want to customize your own Prezto theme–just copy the code changes in this commit: https://github.com/jeffwidman/prezto/commit/9d83811fc7359141a6da232355ce8f066b8a3e82

The only tricky part is if you want the virtualenv name on the right hand side, add $python_info[virtualenv]  to RPROMPT  in line 83, not line 143. I’m not an expert on ZSH scripting, but as best I can tell, this is because Sorin’s theme retrieves the git info asynchronously in the background, and then overwrites the default RPROMPT  in 143 with the output from line 83 when the git info returns.

If you want to see the rest of my Prezto customizations, check out my Prezto fork (main thing I added was a custom module for Atom.io) as well as my dotfiles repo where I manage my ZSH and Prezto config file customizations.


Serving multiple Flask apps via uWSGI + Nginx

Someone on the Flask mailing list asked how to serve multiple Flask apps via uWSGI + Nginx. Anytime you’re working with uWSGI there are multiple ways to do things, but here’s how I do things for RockClimbing.com. I spent several days reading the uWSGI docs + various blog posts around the net, so this should be reasonably correct.

This example shows how to serve multiple Flask apps where each app has its own domain name. If you want to mount multiple Flask apps under a single domain name, see this example in the Flask docs (the pull request hasn’t been merged yet as of time of this writing).

In general, use the uWSGI Emperor, even if you’re only running a single Flask app. The Emperor is a master process that watches over the app(s) to make sure everything is running correctly. Each child app is called a ‘vassal’. If for some reason an app/vassal crashes, then the Emperor will reload it. A number of older blog posts recommend managing your uWSGI apps with supervisord… use the Emperor instead because it offers extra benefits like automatically reloading the app/vassal if you make changes to the vassal’s uWSGI config file.

Create a very basic uWSGI Emperor config called /etc/uwsgi/emperor.ini :

emperor = /etc/uwsgi/vassals

If you want to pass a particular option to all vassals, you can specify the option in the emperor.ini file using the vassal-set parameter.

Create a simple vassal config file in  /etc/uwsgi/vassals/app_name.ini . By default, the config file name will be used for the vassal process name. I manage my vassals using Ansible, so this config has several Jinja2 variables that look like “{{ variable }}”. Just manually replace those with what you need.

You can bind the app to either a TCP socket or a Unix socket. Just make sure Nginx is passing requests to the same socket that the vassal is listening on.

For security, specify a non-root Linux user/group for the vassal to run under. Typically you’ll run each vassal as a separate user/group, and then run the Emperor as root so it can start each app process and then drop privileges before actually serving requests.

Since we’re walking through how to run multiple Flask apps, you’ll want to run each under a separate virtualenv to avoid package conflicts. For example, if one Flask app requires sqlalchemy 0.8 and another requires sqlalchemy 0.9, they’ll need to be in separate virtualenvs. uWSGI makes it easy to specify which virtualenv to run the vassal under by passing the virtualenv  parameter.

For Flask, typically the callable is app , and the module  is the filename where app is defined. You’ll also need to tell uWSGI to cd to the path of the Flask app before trying to import  module .

Lastly, if you do any googling about how to scale Flask + uWSGI, you’ll hit a blog post by David Cramer where he found it better to running multiple uWSGI instances and have Nginx handle the load balancing. The thundering herd problem that David experienced is better solved by setting  thunder-lock = true in your vassal config (or set it globally for all vassals in your emperor.ini config). It’s better to let uWSGI handle the load balancing rather than Nginx because Nginx doesn’t know which uWSGI processes are busy and just round-robins through them when it sends requests. If instead you let uWSGI handle the load balancing, it will intelligently pass requests to the processes that are free.

There’s also a number of options commented out–those are simply reminders to myself that those options exist, but I don’t currently use them.

socket =
# for unix sockets, see chmod-socket and chown-socket

stats =
# use with uwsgitop:
# http://uwsgi-docs.readthedocs.org/en/latest/StatsServer.html

logto = /var/log/uwsgi/%n.log

uid = {{ api_rc_flask_linux_user }}
gid = {{ api_rc_flask_linux_user }}

binary-path = /usr/bin/uwsgi
virtualenv = {{ api_rc_flask_virtualenv }}
chdir = {{ api_rc_flask_path }}
module = manage
callable = app

processes = 2
threads = 4
# to dynamically scale workers see:
# http://uwsgi-docs.readthedocs.org/en/latest/Cheaper.html
enable-threads = true
thunder-lock = true
# http://uwsgi-docs.readthedocs.org/en/latest/OffloadSubsystem.html
offload-threads = 1 # one per CPU is a basic start

# harakiri = 30
# respawn processes after serving 5000 requests (avoid memory leaks)
max-requests    = 5000

# clear environment on exit
# vacuum          = true

# checks python modules every N seconds for changes and autoreloads
# useful in development, avoid in production
# {% if py_autoreload is defined %}
# py-autoreload = 2
# {% endif %}

# limit-as = 512 # ?? for monitoring memory?

# From the uWSGI mailing list:
# 30-40 MB per worker is pretty normal.
# To gain memory you can move to multithreading:
# master = true
# processes = 2
# threads = 2
# thread-stacksize = 512
# should be good enough. Monitoring memory is a good thing, 
# use --reload-on-rss 80 to avoid your app growing up

At this point, test that the Emperor starts and correctly loads the vassals by running uwsgi --emperor /etc/uwsgi/emperor.ini . In production, I just use systemd to manage the Emperor–the uWSGI docs have an excellent example systemd config file.

Next you need to configure Nginx to pass requests to the proper socket. Here’s an extremely simple Nginx config showing the server and location blocks. I run something a bit more complex in production, but this is easier to understand:

# Very useful:
# https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms
# http://blog.martinfjordvald.com/2012/08/understanding-the-nginx-configuration-inheritance-model/

server {
	listen				80;
	listen				[::]:80;
	#listen				443 ssl;
	server_name		api.example.com;

	# Static files should be served through nginx...
	# for simplicity, can handle authentication in Flask as long as X-Sendfile
	# header enabled so Flask generates url, then offloads data streaming to Nginx:
	# http://mattspitz.me/2013/11/20/serving-authenticated-media-with-nginx.html

	# root 					/srv/example.com/static/;

	access_log		/var/log/nginx/api_access.log combined buffer=32k; # TODO syslog and logrotate policy
	error_log			/var/log/nginx/api_error.log; # TODO syslog and logrotate policy

	location / {
			include uwsgi_params;

Feel free to ask questions or suggest improvements in the comments.




MySQL Tuning Tutorial for a Xenforo or WordPress VPS

When I first started managing my own servers, I had no idea how to tune MySQL. I would read various forum posts where people talked about the necessity of ‘proper tuning’, but when I looked at the official docs, I struggled to differentiate between what really needed tuning versus what was an arcane option that only mattered in edge cases.

So here’s the blog post I wish someone else had written.

It’s a longish read, but that’s primarily because I explained why a particular change is suggested… the actual changes are very straightforward and quick. You won’t be a MySQL guru afterwards, but it’ll be good enough for 90% of website admins. And from here you’ll know enough that the official docs will start to make sense.

This is aimed at admins running websites with <5M pageviews a month off a single server–generally blogs or forums. For example, I run a server for a friend that has a handful of forums getting ~3M pageviews a month on a 8GB RAM, 6 core Linode using these tuning recommendations, and the average pageview generally spends <10ms in MySQL query time.

First, most of these settings will be set in a global my.cnf file somewhere on your server. Typically /etc/my.cnf or /etc/mysql/my.cnf

Tuning MySQL starts with understanding the table engine. Basically this is how MySQL manages the data underneath the covers, and is typically invisible to the app developer or SQL analyst.

In the early days, MySQL shipped with a table engine called MyISAM, which is blazingly fast for single-user loads and allowed MySQL to win many database benchmarks that only tested single-user performance. Unfortunately, MyISAM had two problems:

First, it implemented table-level locking, meaning that if one user had a query running against a particular MyISAM table, no other queries could access that table until the first one finished. This doesn’t matter if you just have a single user running queries, but it starts to cause problems as soon as you’ve got more than a handful of concurrent website visitors.

Second, and more important, MyISAM wasn’t fully ACID compliant. It could (and did) cause data corruption in the event of a random power failure. Most admins never hit this problem, but those that did were royally screwed.

A few years later, Percona developed an alternative table engine called InnoDB. InnoDB was fully ACID compliant, so generally the data corruption issue was fixed. That alone makes it my preferred table engine.

Additionally, InnoDB switched to row-level locking, meaning that only the specific row that a query was looking at would be locked. This allowed multiple queries to run simultaneously against the same table, at the expense of slightly slower throughput on any single query. For websites, InnoDB is almost always a better choice than MyISAM.

There there are some built-in tables that MySQL uses to manage itself–these are MyISAM by default and should not be changed. Only change MyISAM tables in your application’s database. Additionally, there are some special MySQL table types like ‘memory’ that should generally not be swapped over to InnoDB. If an application creates a table using one of these alternative table engines, there’s probably a very good reason for it.

The one major constraint of InnoDB was that it didn’t support Full Text indices until MySQL 5.6 (Maria DB 10). Many linux distributions still ship with MySQL 5.5 as the default, so any tables that include full text indices can’t be migrated to InnoDB until the MySQL version is updated.

Sidenote for Xenforo admins: This is why the xf_search_index table defaults to MyISAM–it uses a full-text index. If you swap it to InnoDB, be sure to also disable the ‘

You can set the default table type for new MySQL tables using the default_storage_engine parameter. I strongly recommend setting it to InnoDB. Additionally, it’s easy to swap existing tables from MyISAM over to InnoDB using the ‘ALTER TABLE’ SQL command. You will need to stop the web application from accessing the table while it’s being converted–typically I just stop the webserver, as even the largest tables for most blogs/forums generally don’t take more than 20 minutes to swap if you’ve got fast SSDs.

When you alter to innodb, make sure to specify the row_format. Options are compressed, dynamic, or the default ‘compact’. Dynamic is preferred, ‘compact’ is only default due to legacy reasons. If you are bottlenecked on RAM/disk, but not CPU, then use compressed for tables where compression saves a measurable amount of space (ie, lots of text columns)… For Xenforo admins, the xf_posts table is a good candidate.

If possible, try to completely migrate all MyISAM tables over to InnoDB in your application’s database. That way, you only need to tune InnoDB cache settings, and then let MySQL allocate the cache toward the tables that are used most frequently.

However, if you still have tables in your application database that for one reason or another are required to stay on MyISAM, then try to set key_buffer_size to slightly larger than your largest MyISAM table. If all your application tables are InnoDB, then drop key_buffer_size down to 64M. Don’t drop it all the way to 0 because the internal MySQL tables will use it since they’re still MyISAM (and shouldn’t be changed).

For InnoDB, the most important variable to change is innodb_buffer_pool_size. Basically, this is how much RAM MySQL can allocate to the InnoDB cache. For safety, the default is insanely low to make sure that a default MySQL install won’t kill your server. However, on a production box, you want this number as high as possible without running out of RAM. Ideally, it’s big enough to fit all your InnoDB tables in RAM. Often that isn’t possible, especially on a VPS where typically the webserver, the db, and the linux filesystem cache are competing for limited RAM. In that case, try to set the InnoDB buffer pool to at least several hundred megabytes.

Storytime: A few months after I bought RockClimbing.com, we migrated to a new host and the site promptly fell over every 10 minutes. I’d rented a pretty beefy dedicated box, and the stats showed we had plenty of unused RAM/CPU capacity. I’d never run my own server before, so it took some digging to realize that the underlying issue was the InnoDB buffer pool was still at 64M. As soon as I increased it to a couple of gigs, the problems disappeared.

For the typical forum or blog, a handful of posts get the majority of the traffic. As long as those posts can fit in the InnoDB buffer pool, you’ll typically be fine. For example, I know of a forum with ~30M posts, with total InnoDB table size of ~20gb, but a buffer pool of only ~1GB. Site works just fine because vast majority of traffic hits the most recent 100K posts.

If you’ve got a InnoDB buffer pool larger than 1 GB, then you’ll also need to adjust the innodb_buffer_pool_instances. Adding more buffer pools adds a little more concurrency, although it’s a tradeoff between having many small pools versus a few larger pools. The rule of thumb is a minimum of 1 GB per buffer pool instance. However, MariaDB (explained shortly) defaults to an insane 4 or 8 buffer pool instances once you bump over 1 gb innodb buffer pool, so be sure to manually set it lower. The benefits of more buffer pools drop off pretty quickly–even on rockclimbing.com (my largest site) where the buffer pool is 12GB, I only have 4 buffer pools.

Lastly, if your version of MySQL/MariaDB supports it, enable innodb_save_on_shutdown and innodb_load_on_startup. Basically it pre-warms your cache by saving the cache to disk whenever you shut down MySQL and reading it from disk whenever you start MySQL. That way when you reboot your server MySQL isn’t super slow for the first few pageviews.

Once you swap everything over to InnoDB and then tune the InnoDB Buffer pool, you’re pretty much good for 98% of websites.  Here’s a few more tips though:

What is MariaDB? Another history lesson: MySQL started as open source, then was acquired by Oracle. While Oracle can’t legally make the database closed source, they’ve been trying to close source as much as possible. The guy who started MySQL started a MySQL replacement project called MariaDB. It adds a number of nice features, including a small speed increase.

It’s binary compatible with MySQL, so it shouldn’t cause any issues with your app. It’s also easy to install, just use the pre-packaged RPMs they provide. I’ve been using it on CentOS 7 as a drop-in replacement for MySQL with zero issues.

You’ll want to switch to MariaDB 10, as that’s the equivalent of MySQL 5.6 and adds the full text indices to InnoDB. MariaDB 10 also adds some nifty features like a regex-based search-and-replace. Very handy for updating urls after migrating an old vBulletin forum over to Xenforo.

One MySQL tuning tip that you’ll find in many blog posts is to increase the size of the MySQL Query Cache. However, the benefits are hotly debated, many people say it actually slows things down because in many situations because you’re losing more time checking the cache and finding it doesn’t have what you want than you are by hitting the cache instead of disk. I just disable it most of the time.

Keep yourself out of MySQL encoding hell! I’ve been there, it’s not fun. Set the default character set in the mysql server. UTF-8 is probably what you want. MySQL’s UTF-8 is actually pseudo-UTF8, the real UTF-8 is UTF-8MB4. WordPress switched to MB4 in WP 4.2, Xenforo still on UTF-8. You’ll also want to set the default collation, likely to utf8mb4_unicode_ci.

Sidenote: I hate how MySQL has sloppy engineering. For example, MyISAM not actually being ACID compliant and losing data. UTF-8 not actually being UTF-8. Drives me nuts. If I have the choice, I much prefer PostgreSQL. They may be slower on feature releases, but at least they get it right when they do release something.

Lastly, a security tip. If you’re running MySQL on the same box as your webserver, then make sure MySQL only listens on localhost and rejects all other connections. For remote access, just SSH in, then access MySQL. Most GUIs, including MySQL Workbench (my favorite) support this type of connection.


The emotional side of being an entrepreneur and the values that drive me day-to-day…

I’d done a fair number of interviews lately, mostly about Facebook Analytics and EdgeRank.

So it was a refreshing change when Dale from TrekDek asked for an interview about the emotional side of being an entrepreneur and the values that drive me day-to-day.

Read the full interview.

Speaking at TEDx Zagreb in a few hours…

Here’s the rather random backstory about how I found myself in Croatia preparing to speak on “business networking.”


Eighteen months ago, Ryan Stephens graciously asked me to do a guest post on his blog about my approach to networking. I don’t pretend that I’m an amazing networker who can solve all your problems. Generally I’m upfront with people that, “I can’t solve your problems, but I might know someone who can help you.” 😉

Click here for the original guest post.

A number of people tweeted the post, and I received some attention for it. However, I was completely shocked when few weeks later, I received an e-mail from Nenad Maljkovic, saying that he saw a tweet linking to my blog post, and liked it… and would I be interested in speaking in Zagreb at TEDx?

Not every day you get invited half way around the world to speak based on a random guest post on a friend’s blog.

Thx Ryan, Nenad, Zjelko, and my other hosts here–I have truly appreciated your hospitality.

It is a bit of a dream come true to give a TED talk, as two years ago I titled an intern application “Next Life Goal: Speak at TED”.

How to Hire And Work With a Virtual Assistant

I used to rely heavily on a virtual assistant, and got a lot of questions about the process. This blog post tries to answer them. These days I spend most of my time writing code and very little time managing emails/meetings, so when my last VA graduated college and moved onto a real job, I didn’t look for a new one.

My explicit instructions for hiring a virtual assistant, including copies of my templates are below.

It all works–when my virtual assistant Katie went on vacation for  the entire summer, it took thirty minutes of my time to train someone else–fifteen minutes to explain things the new VA didn’t understand from my templates, and fifteen minutes to give her an e-mail on my Google Apps account. And she’d never worked as an assistant before!

To be clear, a virtual assistant isn’t the same as an outsourced Executive Admin. A friend of mine is the EA for the CTO of a public company, and when I asked about her job, she said a good EA does far more than simply schedule meetings:

It is part of my job to sit in on the CTO’s staff meetings, and to know the direction and goals of our company…. I am the CTO’s partner –and it is my job to make sure that the meetings I allow onto his calendar fit into the bigger picture of what we’re doing.

What I’ve learned from having a virtual assistant:

  • How to be very explicit with my instructions
  • I know better what should be outsourced. It’s almost always faster for me if it’s a one-time thing. But if it’s a repetitive task, it’s probably worth teaching her.
  • I get a heckuva lot more done–she not only removes time, she removes annoyance–that mental friction that comes from having to do tasks that I downright hate (like scheduling meetings.)
  • She not only takes care of things for me, she does them better and faster than I ever could. Face it–just as you’re uniquely talented at some things, you’re uniquely flawed in others.
  • How to teach my employees to teach themselves–it’s rewarding when my VA says she’s learned a ton from working with me!

Computer keyboard with female hands


How I setup my virtual assistant system:

First–what tasks are you going to have them do? How are you going to communicate with them?

I recommend before you start communicating with an actual VA that you take some time and roughly draft out your guidelines for how to manage your calendar, meetings, travel details, and contact and account information. For examples, see the end of this blog post.

Second–who to hire?

  • For a personal assistant, trust is PARAMOUNT. Katie has full access to my Paypal account, credit cards, calendar, e-mail, etc. She could REALLY mess up my life…
  • Reliable college students are often a great fit because you only need to pay them more than the minimum wages they’d be paid for washing dishes… $8-$15 an hour depending on whether they’re an independent contractor or part-time employee.
  • (Despite the naysayers in the comments below, the two college students I’ve hired have said they learned more by working for me than any other boss they’d ever had… plus they valued the flexibility and part-time nature of the job.)


Here are the 10 documents I use. (I just stick them on my personal wiki under a single folder titled “Reference: Assistants”.)

  1. General Information About Being My Assistant–Start Here [Self-explanatory]
  2. How to Add Events to My Calendar [Covers my five calendar categories and reminders]
  3. How to Schedule My Meetings [Addresses the people side of scheduling meetings]
  4. How to Add Someone to Jeff’s Contacts [Self-explanatory]
  5. How to Process My E-mail–Ignore For Now [For now, I find it simplest to handle my own e-mail]
  6. How to Use my Wiki [Explains my folder architecture]
  7. Press Kit [My assistant is responsible for getting press passes to events I want to attend–these links prove that I’m eligible]
  8. Travel Information [Self-explanatory]
  9. Jeff’s Contact Information [Lists contact information for me, my family, and my housemates]
  10. My Accounts [Lists my low-level usernames and passwords for different accounts across the web]

General Information About Being My Assistant–Start Here [Self-explanatory]

(as my VA, feel free to add stuff here as you think of it–ultimately, I want to have a VA document that is clear/self-explanatory/concise…)

Very First Things E-mail: [I copy and paste this into the first e-mail I send to FirstName@jeffwidman.com]

  1. I created a mail account for you – FIRSTNAME@jeffwidman.com.
  2. That account also provides access to your own Google Calendar and Google Docs on the jeffwidman.com domain
  3. I added that e-mail address as an administrator on my wiki.
  4. Go to wiki.jeffwidman.com and login to the wiki using your login instructions.
  5. Find the folder called “r: Assistants” and read the document “General Information About Being My Assistant–Start Here.”
  6. Read everything else.
  7. Go add yourself as a contact in my address book–be sure to include your mobile phone number.
  8. Setup a meeting with me in the next few days–schedule it on my calendar using the wiki instructions.
  9. (Come prepared with an agenda of things you don’t understand from reading the wiki.)
  10. Over the phone, I will give you the secure version of my password–please be VERY careful with this.
  11. We’re off and rolling!


Start by reading these articles: http://delicious.com/jeffwidman/virtual-assistant

My vision of a successful VA relationship:

– You not only handle my administrative tasks, you do so better than I ever could have.
– I tell you what I want, and you figure out how to make it happen.
– You handle my calendar, schedule meetings, and occasionally other tasks.
– You do not prevent people from contacting me, but instead force them to clarify rather than “chit-chat”.
– We both teach each other to collaborate better–suggest technology, interpersonal skills, marketing advice, etc.
– Never make it look like I’m soooo important that I need an assistant. (You’re freeing me to focus on what I do best.)

Task information:

– Deadlines are important. ‘Nuf said. (Let me know if a deadline is unrealistic.)
– Unless specified, assume time zone is Pacific Standard Zone.
– When you first start working, I NEED confirmations that you received the task (””On it—–will be done at Xpm”” is enough).
– When you complete tasks don’t require sending me anything, all I need is an e-mail that says “XXtask done”

Communicating with me:

– Skype: to clarify questions, quick status update, or confirm you received a task
– Phone: Don’t worry about calling me at a bad time. If I don’t want to answer the phone, I won’t.
– E-mail: I generally assign tasks via e-mail–easier to track over time.
– Urgent questions–use: Skype chat, phone, SMS text message. NOT e-mail.
– Non-urgent questions: just e-mail/SMS/skype chat if simple. Call if complex.
(How to leave voice mails: http://delicious.com/jeffwidman/voicemail)

Communicating with others:

– Never masquerade as Jeff.
– If someone wants to talk with me, that’s fine–see the page “How-to Schedule My Meetings”
– Be honest, be tactful, and be yourself.


– You are empowered to make decisions under $50. (Please notify me what you did.)


Paypal is preferred. Let me know if you want something different.

E-mail Signature:

(Note: I’m always open to suggestions. I currently list my Google Voice #, up to you whether to change to your personal #. You are welcome to include your personal website and twitter handle as a way of advertising your services.)

Full Name

Remote Assistant for Jeff Widman

(XXX) XXX-XXXX  | YourE-mail@jeffwidman.com
YourWebsite.com   | twitter.com/YourUserName

How to Add Events to My Calendar [Covers my five calendar categories and reminders]

Be very clear about time zones.

Generally I will forward you e-mails for events to add to my calendar.

  • Unless I make additional notes, assume it’s for my day-to-day calendar.
  • E-mail me a simple “done” so I know you took care of it.
  • Do not create all-day appointments on my day-to-day calendar–either block out the specific time I’m busy (eg, 8am-6:30pm if evening free), or put in followup calendar for reminders. (Otherwise it screws up free/busy information that I share with others).
  • If duration unspecified–use your best judgment…
  • Reminders–I never use popups. E-mail preferred. Text message reminders to important meetings. Look over my calendar defaults to understand my preferences. Use your best judgment…
  • If I’m meeting someone, include the location and their phone number in the title. eg, “Meet Tim (123-123-1234) @ Location”
  • Do not use “Meet X” for community events–“meet” is a hot button for me meaning I need to be there.
  • If it’s a physical location that I don’t regularly visit, please put the physical address in the location so I can quickly Google map it. (If e-mail says “Jason’s house” just put that in the location–I’ll know where to go.)
  • If I e-mail you a link to an event, please put the link in the notes–often these events go under community, and I’ll attend if my schedule’s free (and want to check out the link ahead of time).

Currently, these are my calendars:


For day-to-day stuff that I need to attend.

This is the only calendar I share with my family/key friends, so if I’m busy, it needs to be on here. If I may/may not attend, it’ll probably go under community events.

Default alerts: e-mail day before and sms before any scheduled calls and meetings.

(If it’s important, change to e-mail 3 days before, and text message 10 hours before face-to-face meetings or 20 minutes before telephone chats.)

Community Events

Things I may or may not attend. Generally not important, but I want to know about. Basic settings: E-mail alerts 7 days before (I’ll make a decision then)


This is my tickler calendar to remind me of stuff I need to follow up on at a later date, or decisions I’m postponing. Never put actual events I’m attending here. Always phrase appointments with verbs. (ie, “decide on…, call X about Y, schedule…)

Default reminders: e-mail 3 days in advance and a text message the day of. (Goal: get my e-mail inbox under control, so I don’t have to get texted about stuff)


Where I track family/key friend’s birthdays & anniversaries. These should be all-day events in Google Calendar. Default reminders: 7 day e-mail (I’ll decide whether to get a gift) and e-mail that day (so I can call/e-mail them).


This is where I stick recurring monthly appointments to call specific mentors in my life. Reminders: e-mail the day of. Try to schedule these appointments at least two days apart.

Calendar for VA post

How to Schedule My Meetings [Addresses the people side of scheduling meetings]

Rule #1–use your best judgment, even in spite of these rules…

(I trust you, and I’ll let you know if I disagree.)


  • I start my working day between 8 and 9am
  • I generally quit work between 6pm-1am
  • I work 6-10 hours per day
  • I go to bed around 10:30pm–although not uncommon to pull an allnighter.
  • I work best in three to five hour chunks–thus I prefer to batch a bunch of meetings/calls together.
  • As a strong extrovert, I’m normally quite energetic after a face-to-face breakfast/lunch meeting, and like to have the next few hours free to work off that energy
  • I prefer to keep my evenings (after 5:30pm) unscheduled
  • My life is full, but my schedule is currently very flexible (I like to attend lunch-time frisbee twice a week)
  • Optimum schedule: Lunch T/R, breakfast any weekday
  • You have full access to my calendar, so schedule wherever works best–we’ll refine over time
  • (I work hard to keep my calendar updated all the time. If something needs to be rescheduled, I’ll let you know.)

Responding to Meeting Requests:

  • Currently, most meeting requests from others are people reaching out and looking to connect via phone…
  • I love talking with them, but want to make sure they’re serious about the call.
  • Ask which topics they would like to discuss, and put in the calendar description notes.
  • Here’s a sample e-mail I’ve used before:


This is YourFirstName, Jeff’s virtual assistant–I manage his calendar and schedule meetings.

Jeff said he appreciated your reaching out to him–he would love to chat with you.
He normally finds a 20-30 minute phone call most efficient.

However, Jeff doesn’t want to waste your time, so he asked that you e-mail me 3 potential discussion topics/questions.

Please send me your phone number, and two good days/times to call you this week (include time zone). I’ll set an appointment on Jeff’s calendar and get back to you.

By the way, I checked out your blog–very nice! [totally optional–only if true]



Scheduling meeting requests I’ve confirmed:

  • If they respond, email Jeff the confirmed meeting time and location–BCC’ing often works well.
  • If they ignore you. Send a 2nd e-mail three days later, and ask if they saw it–often, they just forgot to respond. Ask me if you don’t hear back after two e-mails.
  • When you communicate with anyone, be clear you’re merely facilitating a meeting–you’re not trying to make Jeff seem busy/impressive. Never be pushy.
  • Here’s a great sample e-mail:


1. How about <meeting place> at <time>?  (You initiate the meeting place.)

2. When would you like to get together?  (Let him set the date.)


  • See the “How to add events to my calendar” wiki page
  • ***Important*** Make the title “Meet w/NAME (PHONE #)”
  • Give them my  Google Voice number
  • If we’ve never met, they can see a picture of me here: http://www.jeffwidman.com/blog/about/
  • While most lunch meetings last 1 hour, I prefer to build 1.5 hours into my calendar just in case things are going really well.
  • I’m not rich, but don’t want to meet in McDonald’s either–and I try to always pickup the check. (I find having them suggest a place solves the problem.)
  • I prefer lunch meetings within fifteen minutes drive from where I work (shorter is better–currently I work from home). This way I’m gone from work for a maximum of two hours.

Restaurant Preferences:

  • I enjoy all types of food–ask if they have a favorite.
  • (Sushi, and other semi-adventurous foods are always fun.)
  • I prefer to have them suggest a place–unless they’re from out of town, then ask me.
  • In my Google Docs, under Reference, there’s a spreadsheet of Bay Area Restaurants–please add to it when I visit a new place.
  • If they don’t know, call Jason XXXX or Andrea XXXXX (in my address book), tell ’em you’re my Assistant, and ask for ideas–they’re both foodies and know me/my style.

How to Add Someone to Jeff’s Contacts [Self-explanatory]

How to Process My E-mail–Ignore For Now [For now, I find it simplest to handle my own e-mail]

How to Use my Wiki [Explains my folder architecture]

Press Kit [I (used to) write irregularly for VentureBeat & Mashable. My assistant is responsible for getting press passes to events I want to attend–these links prove that I’m eligible]

http://delicious.com/jeffwidman/articles Examples of articles Jeff has written, useful when applying for press passes.

http://delicious.com/jeffwidman/press-kit for random stuff. (Website with articles/content by or that mention Jeff.)

http://delicious.com/jeffwidman/interviews for when people have questions about interviewing me.

Travel Information [Self-explanatory]

(Right now, I travel infrequently, so we’ll handle plane tickets, hotel rooms, etc on a case-by-case basis.)

All travel related emails–like itineraries, hotel rooms, conference registration numbers, etc–should be labeled with the “Travel Details” label–that label maps to a folder on Jeff’s iPod and phone so that Jeff can easily pull them up on his phone when he needs them.

Whenever you buy plane tickets, please forward the itinerary information to “plans@tripit.com” (Unless I specify the trip is to surprise someone–my Tripit account makes my travel plans publicly available.)

Tripit( www.tripit.com ) Account information can be found in Lastpass.

Jeff’s Contact Information [Lists contact information for me, my family, and my housemates]

Public Contact information-Can give to anyone:

E-mail: jeff@jeffwidman.com

Google Voice Number: (XXX) XXX-XXXX

Private – Do not give to anyone:


Jeff’s personal cell phone:
Dad’s cell phone:
Parent’s home phone:
Sister cell phone:

My home address:

Housemate #1 Cell Phone:
Housemate #2 Cell Phone

My parent’s home address:

Time where I live:
[I used an embeddable clock widget that shows the time and date where I live. Handy if your VA lives in a different time zone.]

My Accounts

I used to list my low-level usernames and passwords for different accounts across the web, now I just stick it all in a shared Lastpass folder.

I’m officially a college graduate!

Hey all–I officially graduated college in the middle of September. Thx for all the support, encouragement, and friendly ribbing… :-)

PS: Out of all the time I’ve spent learning how to negotiate, this was by far the most useful 90 minutes: Stanford Podcast with Joel Peterson.

Facebook Newsfeed Optimization

Back in May of ’09, I began managing all the Facebook marketing for Mint.com, and in four months I quadrupled (4x) traffic from Facebook–>Mint.com. Soon, more and more companies wanted me to manage their Facebook marketing…

Eventually, I received so much work through word-of-mouth that I hired a few of my really smart friends and started BrandGlue.com, an agency specializing in Facebook marketing.

We help companies use Facebook to build brands and sell products–primarily through Fan pages.

A few of our clients:
• Intel
• Microsoft
• Mint.com
• David Allen (“Getting Things Done”)
• Kiva.org
• SlideShare
• ICanHasCheezburger/FailBlog.org

We optimize for the Facebook newsfeed algorithm, increase conversions from visitors–>fans, and integrate Facebook into the rest of your marketing (e-mail, website, offline, etc).

Latest success story: We grew facebook.com/failbooking from 16K fans to 41K fans in one week–with ZERO ad spend.

The 21 questions my friend asks me every night over the phone

Several months ago, I attended the GTD Conference, where I heard Marshall Goldsmith describe what he called “Peer Coaching”:

Every day Jim asks Marshall the same 24 questions. Every day Marshall asks Jim the same 17 questions. Marshall and Jim each have a spreadsheet of each other’s questions where they record for each other the answers: ‘yes’, ‘no’, or a number. Structuring the questions in this way keeps the phone call moving. Each phone call lasts only a couple of minutes.

I thought it was a fantastic idea, so for the past three months, Brian Russell and myself have had a similar phone call every night.

There were three rules:

  1. We each wrote our own questions.
  2. We committed to call each night (except for when Brian was in South America)
  3. All the questions had to be specific–answerable with a yes/no or number between 1-10.

What we learned:

  • Writing good questions is hard
  • Honestly answering these questions is even harder–I’m confronted with failure on a daily basis
  • The emotional connection of a phone call is SUPER important for accountability–when Brian was in South America, we tried using a spreadsheet, but I never remembered to update it.
  • Focus on simplicity. If you can’t finish the phone call in 5 minutes, you’ll start dreading it (of course, most nights we end up talking for fifteen minutes, but that’s just bouncing ideas around and being friends.)
  • The call is a great way to celebrate successes and reboot from failures–on a daily basis.

Brian and myself became friends in middleschool, and we’ve built a close friendship since then. I respect his reliability, his advice, and his sensitivity. Reliability is also a function of interest. Brian spent some time thinking about it, and decided this was something he was interested in enough to commit to for a month, and we’ve just kept going strong since then.

Jeff’s Questions:

  1. Did you accomplish the three most important tasks on your todo list for today?(Have you set three todo’s for tomorrow?)
  2. How many hours did you work on tasks that would directly make money?
  3. Did you spend time reading/learning for the long-term?
  4. How much time did you waste on e-mail/the web?
  5. How many times were you late to meet someone?
  6. Did you compliment at least three people today?
  7. How many times did you criticize?
  8. How many times did you try to prove how smart you are?
  9. On a scale of 1-10, were you a non-interrupting listener, relevant storyteller, and intentional conversationalist today?
  10. (If Fasting day) Did you fast today?
  11. What was one way you failed today?
  12. How many times did you have a lustful thought about a woman?
  13. How many times did you worry today (like about the future)?
  14. Did you read your Bible today?
  15. Did you spend dedicated time in prayer today?
  16. How many people did you witness to today?
  17. How many pushups?
  18. Did you brush your teeth?
  19. Your plan between now and bed?
  20. By whose power did you live and for whose glory?

Brian’s Questions:

  1. Have you kept your eyes pure?
  2. Have you kept your thoughts pure?
  3. Did you read your Bible?
  4. How many times did you pray?
  5. Did you read a book?
  6. Did you procrastinate your 3 priority tasks?
  7. Have you set three tasks for tomorrow?
  8. How many hours did you work for money?
  9. How many times were you late?
  10. During conversation, were you proactive? (leading, affirming, exhorting, rebuking)
  11. How many pushups?
  12. Did you brush your teeth?
  13. Your plan between now and bed?

Painting corners: How do you make decisions when your choices have unknown pros/cons?

(My secret sauce for decision-making. So simple… I must be stupid to benefit from this.)

The background:
For the past three summers, I’ve spent a week in the outdoors with my friends Ryan and Matt (one of those rare types with zero Google presence). We’ve gone backpacking, canoing, overseas, etc. These trips were great fun, rebooted my perspective with a week completely offline, and helped me build some incredible friendships.

That is, until last summer. Matt was starting school at the end of August, and Ryan was working until early August. And it just so happened that I’d been offered the chance to spend August at TechStars.

Decision: TechStars or my friends?

I spent two weeks agonizing over the decision, knowing that I was picking between two attractive options. The worst part was I didn’t know exactly what would be the outcome of my TechStars experience, nor whether the three of us could get together over Thanksgiving (the only potential compromise.)

How do you make decisions when your choices have unknown consequences–when you don’t know the pros/cons?

You paint the corners. ‘Cause you almost always know the absolute best and absolute worst. You just don’t know the probabilities.


This oversimplifies complicated decisions into a binary outcome.

Eg, if I go to TechStars, the best outcome included massive learning, extending my network, and connecting with Matt and Ryan over Thanksgiving. The worst outcome was a month in Boulder minus the opportunity cost of staying home.

If I go with friends, the best outcome was making money for a few weeks, plus spend a week with friends. The worst that happens is I make a little money, spend a week with friends, and forgo opportunities from TechStars.

The pros/cons are unknown–or rather, known outcomes with unknown probability..

I chose TechStars, and was also able to connect with my friends over Thanksgiving.

(Note: I first read about “Best-worst case analysis” in Ben Carson’s book, Take The Risk–thanks Jerome!  I’ve found these four questions make most of my decisions very easy.)

Steve Blank provides another decision-making heuristic:

Think of decisions of having two states: those that are reversible and those that are irreversible. An example of a reversible decision could be adding a product feature, a new algorithm in the code, targeting a specific set of customers, etc. If the decision was a bad call you can unwind it in a reasonable period of time. An irreversible decision is firing an employee, launching your product, a five-year lease for an expensive new building, etc. These are usually difficult or impossible to reverse.

My advice was to start a policy of making reversible decisions before anyone left his office or before a meeting ended. In a startup it doesn’t matter if you’re 100% right 100% of the time. What matters is having forward momentum and a tight fact-based feedback loop (i.e. Customer Development) to help you quickly recognize and reverse any incorrect decisions. That’s why startups are agile. By the time a big company gets the committee to organize the subcommittee to pick a meeting date, your startup could have made 20 decisions, reversed five of them and implemented the fifteen that worked.