             force  : false   # don't use local cached or value obtained
             update : false   # make server recompute state (forces switch to stable state)
             cb     : required
-        dbg = @dbg("state(force:#{opts.force})")
+        dbg = @dbg("state(force:#{opts.force},update:#{opts.update})")
+
+        if @_state_time? and @_state?
+            timeout = STATES[@_state].timeout * 1000
+            if timeout?
+                time_in_state = new Date() - @_state_time
+                if time_in_state > timeout
+                    dbg("forcing update since time_in_state=#{time_in_state}ms exceeds timeout=#{timeout}ms")
+                    opts.update = true
+                    opts.force  = true
+
         if opts.force or opts.update or (not @_state? or not @_state_time?)
             dbg("calling remote server for state")
             @_action

    opening:
        desc     : 'The project is being opened, so all files and snapshots are being downloaded, the user is being created, etc.'
        to       : {}
        timeout  : 60*60
        commands : ['status', 'mintime']

    starting:


    _update_state: (state_error, cb) =>
        dbg = @dbg("_update_state")
        if @_update_state_cbs?
            dbg("waiting on previously launched status subprocess...")
            @_update_state_cbs.push(cb)
            return
        @_update_state_cbs = [cb]
        dbg("state likely changed -- determined what it changed to")
        before = @_state
        @_command
            action  : 'status'
            timeout : 60
            cb      : (err, r) =>
                if err
                    dbg("error getting status -- #{err}")
                else
                    if r['state'] != before
                        @_state = r['state']
