diff --git a/cmd/status/status.go b/cmd/status/status.go
index ebbd88aa0de12a9d3a9cd6b4cbe5fd9967a5093c..9bc5dc942495e3da65fce2d5dbd73f064510e59a 100644
--- a/cmd/status/status.go
+++ b/cmd/status/status.go
@@ -4,10 +4,12 @@ import (
 	"encoding/json"
 	"flag"
 	"fmt"
+	"io/ioutil"
 	"log"
 	"net/http"
 	"net/url"
 	"os"
+	"os/exec"
 	"strings"
 
 	"git.autistici.org/ai/status"
@@ -24,17 +26,45 @@ var (
 	doList  = flag.Bool("list", false, "list all open events")
 )
 
+func getMessage() string {
+	// The update message can be passed as command-line arguments.
+	msg := strings.Join(flag.Args(), " ")
+	// Otherwise, invoke $EDITOR on a temporary file.
+	if msg == "" {
+		tmpf, err := ioutil.TempFile("", "update-")
+		if err != nil {
+			log.Fatalf("Could not create temporary file: %v", err)
+		}
+		tmpf.Close()
+		defer os.Remove(tmpf.Name())
+
+		editor := os.Getenv("EDITOR")
+		if editor == "" {
+			editor = "/usr/bin/vi"
+		}
+		log.Printf("running %s %s", editor, tmpf.Name())
+		cmd := exec.Command(editor, tmpf.Name())
+		cmd.Stdin = os.Stdin
+		cmd.Stdout = os.Stdout
+		cmd.Stderr = os.Stderr
+		if err := cmd.Run(); err != nil {
+			log.Fatalf("Update aborted: %v", err)
+		}
+
+		msgBytes, err := ioutil.ReadFile(tmpf.Name())
+		if err != nil {
+			log.Fatalf("Could not re-read update message: %v", err)
+		}
+		msg = string(msgBytes)
+	}
+	return msg
+}
+
 func main() {
 	flag.Parse()
 
-	// The message is just passed as command-line arguments.
-	msg := strings.Join(flag.Args(), " ")
-
 	// Check for conflicting options.
 	if !*doList {
-		if msg == "" {
-			log.Fatal("No message provided")
-		}
 		if *isNew {
 			if *doClose {
 				log.Fatal("--new and --close can not be specified together")
@@ -42,6 +72,9 @@ func main() {
 			if *eventId != "" {
 				log.Fatal("--new and --id can not be specified together")
 			}
+			if *title == "" {
+				log.Fatal("New issues must have a title (use the --title option)")
+			}
 		}
 		if !*isNew && *eventId == "" {
 			log.Fatal("You need to provide at least one of --new (to create a new event) or --id (to update an existing one)")
@@ -83,6 +116,8 @@ func main() {
 		return
 	}
 
+	msg := getMessage()
+
 	var path string
 	v := make(url.Values)
 	v.Set("author", *user)