Zenbox is a personal productivity suite based on Theory of Constraints. It contains the following components:

In addition, Zenbox provides FunX - a static analyzer that generates tasks for software developers.

Time management

Zenbox prevents procrastination by setting a time limit for each task. If you don't complete the task on time, Zenbox pushes it back into the queue & switches to the next task. You are motivated to produce a result that is imperfect but good enough.

Zenbox allows you to switch between different task streams to cover all areas of your life. By default, you can switch between Work, Rest, Exercise, Socialize. In addition, you are encouraged to define your own task streams. Each task stream is associated with a time interval that specifies when this stream should be active. If no task stream is associated with the current time interval, Zenbox uses the default task stream: "Rest".

Each task stream downloads the tasks from external apps. You can connect messengers, email inboxes, calendars, project management systems & more. This allows you to create a single, unified task queue from different sources.

Zenbox uses a separate connector for each external app. Every connector can read the tasks from the app - but in addition to that, it can also write the task results back into the app. This allows you to directly update the data in the app (for example: send an email, update a spreadsheet row, create a new record in the database).

Zenbox doesn't allow you to see the all tasks on one page. Instead, it displays only the first task from the currently active stream. In addition, Zenbox starts the timer automatically, without waiting for you. It allocates a limited time to each task, after which it "rotates" to the next task. If you haven't completed the task on time, the system moves the task to the back of the queue.

Zenbox requires you to associate each time interval with a task stream. During that time interval, you will only see tasks from this stream.


  • You save time by not choosing the next task (the system sorts the tasks automatically by the time of arrival).
  • You are motivated to skip procrastinating & start working on the task (otherwise the system would start & stop the timer automatically, marking the task as incomplete and moving it to the back of the queue).
  • You are motivated to complete the task (otherwise the system will send a default result to an external system - for example, if the task were "Reply to email", the system would send a default answer: "Sorry, I can't reply now. Please send your message again later.").

How to start

You can use Zenbox with just a timer + self-discipline. Here is how:


  1. Define a list of task stream names (the areas of your life that you need to give time to)
    1. Feel free to use the default names in addition to your own:
      1. Work
      2. Exercise
      3. Socialize
      4. Rest
      5. Eat
    2. Ensure each name is a verb (rationale: you need to define what you're going to do, so it must be a verb)
  2. Define your task streams as recurring events in calendar:
    1. Create a new Google Calendar
    2. Create task streams as recurring events
      1. Ensure availability is set correctly:
        1. "Busy" if you don't want other people to schedule meetings with you during this task stream
        2. "Free" if you do want (or don't know if you want) other people to schedule meetings with you during this task stream
      2. Minimize the amount of task streams (less is better)
      3. Ensure there is at least one task stream called "Rest"
      4. Ensure the task streams cover the entire schedule (no gaps)
    3. Associate a task source with each task stream except "Rest"
      1. Read the following notes:
        1. A task source is an external application where you see your tasks (e.g. instant messenger, email inbox, JIRA, Slack, Salesforce, ...)
        2. If you want to create a task source that aggregates multiple individual sources (e.g. for "Answer all messages" task stream), you can use multiple URLs or a single aggregate name (e.g. "Messengers")
      2. Put the task source identifier into event description
        1. Notes:
          1. A task source identifier can be any string:
            1. A web app URL (recommended)
            2. A desktop app name
            3. An aggregate name (e.g. "Messengers")


  1. Pick the current task stream:
    1. Go through your calendars from top to bottom:
      1. If there is an event for current time, use this event as task stream
    2. If there is no event for current time in any of your calendars:
      1. Execute Setup (ensure there are no gaps between task streams)
      2. Execute Run again
  2. Pick the current task from the task stream
  3. Choose the task duration
    1. Set a timer for 5 minutes
    2. Choose the task duration
      1. Don't think about other tasks; you will get to them later
      2. The more important the current task, the more time you should allocate to it
    3. If the timer runs out before you choose the duration: choose the default (1 hour)
      1. Don't spend more time on choosing the task duration
  4. Set a timer for task duration minus 5 minutes
    1. Note: you will use those 5 minutes to publish the task result (e.g. push the commits, publish the documents, send messages from drafts).
  5. Work on the task:
    1. Ensure you always have a structurally complete result
      1. It may have "TODO" markers, but the general idea must be understandable by the person who receives the task result.
  6. When you finish the task:
    1. Publish the task result
    2. Submit the task result for review
    3. Stop the timer
  7. If the timer runs out before you finish the task:
    1. Mark the task as failed
    2. Execute the same actions as in "When you finish the task"
      1. Don't spend more time on improving the task result. Instead, accept the failure & continue to the next task. This experience will help you to stop procrastinating & learn to produce a good-enough task result within a limited time

Submit the task result for review

  1. Send the task result to your teammates via group chat.
    1. If you don't have teammates: create a group chat with people who are working on similar projects.

How to improve

For teams, Zenbox can be implemented as a web application with a minimal UI. The team members can't add the tasks manually - the admin must set up task management to source the tasks from external apps.


How can I set my rest time?

You can associate a specific time interval with a task stream that contains only one task: "Rest". You're encouraged to take as much rest as you actually need.

How can I prioritize the tasks?

  1. You can prioritize a single task stream by increasing its time interval.
  2. You can autocomplete a task using an autoresponder.
  3. You can't prioritize a single task within a stream. This increases your total productivity, because you will complete both the urgent tasks and the important tasks within a single task stream. It's important to work on important tasks, so Zenbox disallows manual prioritization (which is ).

What should I do in an emergency?

You can activate "emergency mode". While it is active, Zenbox will add extra fields (customizable by you) to each default response.

Zenbox will continue producing tasks. If you can't complete a task before timeout, Zenbox will send the default response.

The "emergency mode" doesn't pause Zenbox, since the emergency task doesn't pause the time.

How can I plan meetings?

  1. Create a meeting in your calendar.
  2. Connect your calendar to Zenbox.
  3. Ensure the calendar for meetings has a higher priority than the calendar for normal task streams.

Zenbox will treat the meeting as a separate task stream. When the time comes, it will remind you to join the meeting.

Warning: meetings decrease productivity. You can avoid meetings with the following tactics:

  • Ask the person who proposed the meeting to send you a summary of what he wants to say & promise to respond to him (most often, people schedule meetings because it gives them a guaranteed time slot to present their ideas).
  • Hire someone to take the meetings for you.

How do I choose the time interval to associate with a specific task stream?

Trust yourself. Only you can estimate how much time you need to spend on your goals. Also, you can change it later.

There is no objective estimator - no objective reward function. Your intuition is just as good as any formal algorithm.

If you want extra assurance, you can verify that your intuition is consistent (doesn't produce any contradictions). For that, you can write down your assumptions (axioms), then look for potential conflicts. In addition to your personal axioms, you can add an extra one: "every person is mortal". This axiom will free your mind from looking for a perfect solution, because you won't have perfect information, and other people won't have it either.

Why is Zenbox so harsh?

No pain - no gain.

If you want something you don't have, you need to give up something you don't want.

What do you really want?

Task management

Zenbox unifies tasks & messages under a single request-response paradigm.

Zenbox requires you to submit task results, which are forwarded to external systems. For example, if the task were "Reply to email", the system would expect the task result to be an answer to the email, and it would send the answer on user's behalf via email server. This allows to use Zenbox as a proxy between you and the external task sources (email, messengers, Salesforce notifications, GitHub issues, Google Sheets rows, ...).


  • push - add a task to the queue
    • Inputs:
      • Task push token (JWT string) (includes username)
      • Task description (JSON string)
    • Output:
      • Task pull token (JWT string)
    • Default implementation
      • Add a new task "Implement a handler for task" to a FIFO queue
  • pull - remove an task from the queue
    • Inputs:
      • Task pull token (JWT string)
    • Output:
      • Success status (bool)
  • get - get a task
    • Inputs: none
    • Output:
      • Task description (JSON string)
    • Default implementation
      • If task queue is not empty: Return the task from the queue
      • If unreviewed task results queue is not empty: Return the task "Review a task result"
      • Return the task "Automate the task type"
        • Choose the task type by statistics (most incomplete tasks first)
    • Notes
      • get command opens a text editor for making a set of changes to the system code
        • The user sees the default code (respond with an empty string) pre-written in the editor
        • The user can freely edit the code
        • The user can save the new code only if it passes the typechecker
        • The user can close the editor if the current code has been saved ("complete the task early")
        • The editor will self-close after a timeout (can be adjusted as a separate task at the end of the day)
      • The user can react to the task in the following ways:
        • Provide a direct response


Data source

A data source is an API that pushes the tasks into your streams.


  • Text messengers: WhatsApp, Telegram, Facebook Messenger, ...
  • Email servers: Gmail, Hotmail, company email server, ...
  • Issue trackers: GitHub, Trello, JIRA, ...
  • CRMs: Salesforce, Pipedrive, ...


Autoresponder is a function that generates automatic responses for certain messages. It saves your time by keeping simple messages away from your inbox.

Project management

Zenbox helps you make project-level decisions, verify them with simulations, then automatically send the tasks to employees.


  • Save time on micromanagement: the tasks will be displayed in the web interface + sent automatically by the Telegram bot.
  • Write better plans: each "business plan" will be very detailed - down to individual task level.
  • Change plans faster: each team member will be able to suggest a change to the plan by sending a pull request on GitHub.
  • Show your plans: each team member will be able to see the big picture (after a crash course in TypeScript 😈 )


FunX is a static analyzer that tells software developers what functions to write. FunX minimizes the total development time by instructing developers to implement partial functions, and telling them how to extend existing partial functions to cover a progressively larger part of their input domains.

FunX is based on an important observation: "In practice, a function will never receive its every possible input". In other words: there is always some obscure input that won't be seen by the function. This is true for every function with an infinite input domain (for example: the add function, which has an infinite input domain of pairs of natural numbers, will never see every possible pair of natural numbers).

This fundamental property allows to split a complex task into simple tasks by splitting a total function into partial functions. Partial functions are easier to implement because they have smaller input domains. FunX generates new input domains from execution statistics and the axiom of continuity (which states that the probability of seeing a new input depends on the probability of seeing a previous input that is "close to" the new input).



Main idea: solve a general case by solving special cases, then combining special solutions into a general solution.


  • An algorithm for automatic generation of special cases from a general case ("partialization")
  • An algorithm for automatic generation of a general solution from special solutions ("reconciliation")

The special cases are generated by the machine. The human only needs to provide partial solutions for these special cases.

  1. Transform the question into a list of axioms (logical statements that describe the problem)
    1. Axioms must include axioms about the types of the variables
    2. Axioms must not include any axioms that are not directly given by the question (see why)
      1. It's possible to ask the author of the question to clarify the question (= specify additional axioms).
  2. Transform the list of axioms into a generator that yields a list of lists of premises (logical statements that describe a special case of the general problem) (yes, generator yields a list of lists: every element of the top list is a special case, which is represented as a list of premises)
    1. Premises must include every axiom
    2. Premises must include at least 1 additional constraint that reduces the full question to a partial question (reduces the general case to a special case).
    3. Premises must be unique across the list (generator must filter the premises that are considered equivalent under the list of axioms).
  3. Transform premises into partial solutions (1 partial solution for 1 premise)
  4. Initialize the total solution to the first value from the generator of partial solutions.
  5. For each partial solution from the generator:
    1. Reconcile the current total solution with a new partial solution: each

The "natural language" steps are only needed for communication with other humans who are not parsers.


  • A validator function is not needed: the question must be transformed to a list of logical statements (axioms) that completely describe the problem.

No axiom for output type


  1. You are given the question: "What is the root of the square equation a*x^2 + b*x + c = 0?"
  2. You are tempted to write the axiom: answer has type "real" (answer: real). However, if a = 0 and b = 0 and c != 0, the answer has type absurd (or "empty", "bottom"), because the equation reduces to c = 0, which contradicts the premise c != 0.
  3. You are tempted to write the axiom: x has type "real" (x: real). However, if b = 0 and sign(a) = sign(c), then x has type complex, because the equation reduces to x = sqrt(-1 * c/a).

Therefore, it's incorrect to assume the axioms that are not given by the question (axiomatize the type of any variable, including answer).


Word is a list of characters without punctuation.


  • main
  • add
  • 42
  • 0
  • +
  • =


  • Punctuation characters are .,() and whitespace characters.
  • In the context of context-free grammars, a word is called a symbol.


Phrase is a list of elements separated by whitespace and enclosed in parentheses. Every element is either a word or a (nested) phrase.


  • (main)
  • (add 2 2)
  • (add (add 1 1) 2)
  • (= (add 2 2) 4)
  • ()


  • Yeah, it's a LISP.


Type is a phrase that describes another phrase.

Type can be defined as a list of constructors ("actions" in machine learning).

Type can be defined as a producer function:

  • Input: a list of existing type elements (can be an empty list)
  • Output: a list of existing type elements appended to a list of new type elements

Type can be defined as a reducer function (a validator):

  • Input: a phrase to be typechecked
  • Output: if the input passes the typecheck, then an empty phrase, else a non-empty phrase


Dict (or "dictionary", or "static map", or "associative array") is a list of pairs where:

  • The first element is the input phrase.
  • The second element is the output phrase.


  • The first element is the name.
  • The second element is the meaning of the name.


  • The first element is the pointer.
  • The second element is the value.

The input and output phrase are not equal syntactically, but they are equal semantically: after the function is applied, the input becomes equal to output.


Example dict for add function:

(1 1) 2
(3 5) 8
(7 7) 14

Example dict for evaluate function:

(add 1 1) 2
(add 3 5) 8
(add 7 7) 14

Example dict for length function:

"a" 1
"ab" 2
"abc" 3

Example dict for get_function_body function (see also: [Add function evaluation]):

add (
          (next @1)
          (add @1 (next $2))

Example dict for fibonacci function:

0 1
1 1
2 2
3 3
4 5
5 8
6 13
7 21

Example dict for number_to_expression function:

0 zero
1 (next zero)
2 (next (next zero))
3 (next (next (next zero)))


Def (or "definition", "implementation", "body") is a list of phrases associated with a specific word. The executor should replace the word with its def when transforming the input into output.

In other words:

  • An executor may read the def and write a program that can read the dict inputs and write the dict outputs (= calculate outputs from inputs)


  • Def is a general form of the dict
  • Def depends on the executor, which interprets some words of the def in an executor-specific way



Executor is a real-world entity that turns input phrases into output phrases.

Initial executor

Initial executor is an executor who triggered the chain of transformations of the input phrase.


Expression is a phrase that can be used by a specific executor to produce a non-empty phrase.

Alternative definitions:

  • Expression is an input that results in a non-empty output (for a specific executor).


  • Every expression is a phrase, but not every phrase is an expression. The executor determines whether a specific phrase is an expression.
  • Sometimes we can't tell whether a specific phrase is an expression (e.g. when the target executor is not well-researched).


Variable is a word that must be replaced to turn an invalid phrase into an valid phrase.

The replacement must be an expression.


  • Rephrase the definition, so that it doesn't rely on execution


Function is a list of expressions with at least one variable.

Standard function

A standard function is a function that is defined in the standard library of the language.

Examples for TypeScript:

  • Arithmetic functions: +, -, ...
  • Boolean functions: ==, ===, <, >, &&, ||, ...

Task stream

Task stream is an object that generates the tasks from external apps.


  • URL - the url for downloading the tasks
  • API token - the authentication token for downloading the tasks
  • Default task duration - the time interval in milliseconds that is used if the user doesn't specify the task duration

Safe rename

Safe rename is an operation that replaces a single word with another word that's not present in the phrase (similar to "alpha-conversion").


  • Safe rename preserves the count of unique words in a phrase.

Words Are Voids

A mathematical phrase has an interesting property: the meaning is the same under a safe rename. Let's see what that means.

Suppose we have a phrase: (next zero). If we rename next to after, we will have (after zero). The meaning of the phrase is the same - we just renamed a word. Let's translate it into French: (après zéro). The meaning still the same - but notice that the words are meaningless to a non-French speaker. We can replace words with characters: (x y). We can replace characters with numbers: (1 0). The meaning is still the same, so we can conclude:

  • The words don't define the meaning of a mathematical phrase.
  • The positions of the words define the meaning of a mathematical phrase.


We make decisions to take actions. Therefore:

  • Decisions are descriptions of what actions to take.
  • Decisions are lists of instructions.
  • Decisions are programs.

This realization has profound implications for programmers:

  1. We can make decisions by writing programs. We just need to learn how to write decision-specific programs in our favorite programming language.
  2. We can use any Turing-complete programming language. We just need to choose a language which simplifies making decisions (more on that later).
  3. We can mix human instructions with computer instructions. We just need to use a special interpreter to run programs with a mixed instruction set.

The ability to write mixed programs for humans/computers is very powerful:

  1. We can build companies by writing code. We can automate setting tasks for employees, validating their work results, collecting money from customers & distributing money to employees. This is possible today - there are APIs for setting tasks & sending money. We just need to make decisions about the parameters of the API requests.
  2. We can build governments by writing code. We can automate setting tasks for government officials, verifying their work results, collecting taxes from some citizens & distributing taxes to some other citizens. We can also require the laws to be expressed as theorems, which must be proven by axioms (the Constitution).

Excited? So am I. Join our group to ask questions & learn to use this power of making decisions by writing programs.