Closed sayanarijit closed 2 years ago
Capturing information will be mind
's primary focus (as currently is), because
it's the most crucial part, since I can only process information when I capture
them.
When I encounter some information that I want to capture, I don't want to lose my focus from the current task at hand. Hence, I want the experience to be as effortless, distraction-free and efficient as possible.
I think mind
's current UI design and input mechanism is capable enough.
However, an even cleaner version is possible where I don't see the previously submitted information. Rather, I only see an input box where I can submit a paragraph (with details if required) and when I do submit, I get some feedback.
Which means, it's possible to further improve the UI/UX for an even better experience. So, it might come in handy to allow hacking the UI/UX via some configuration (and maybe plugin) system.
So, at the core, mind
will only provide an interface via which an input
reader can submit information. And a renderer that can render the captured
information.
The input reader and the renderer should be able to receive and acknowledge live updates asynchronously.
Input reading should have the highest priority and rendering should be optional.
The information will be submitted in plain text format to keep things simple. The first line will be considered as the title (required, unique) and the following lines will be considered as the body (optional).
The input (both title and body) will be raw i.e. no special format, syntax, metadata or anything that contain some meaning for a tool or algorithm, will be supported. But I should be free to use my preferred format, syntax or attach metadata to the information to help me when I visit it later.
The mind
CLI tool will come with a default implementation of the input
reader and UI renderer for the terminal, but should be able to run in headless
mode, only exposing the API via different channels, so that other tools can do
the job too.
Sometimes I might want to skip the capture step and go directly to the next step. For this, there should be easy ways to move the current input to the next step at every opportunity.
When I need to capture information,
I might not be in the terminal. So, I need a key binding, widget or desktop
icon to pop open mind
in a terminal window whenever I need.
I might not be on my laptop. So, a I need a mobile app or widget where I can
take/forward/share the note and sync via LAN, Bluetooth or some secure
internet service when I get back to my laptop. The information will get
deleted from the mobile when mind
acknowledges the sync completion.
It should support manual deletion. But mind
should remind me to sync when I
open it in my laptop after a certain time.
Bonus: Support voice messages and automatic sync using digital storage
services.
I might not want to install another app just to keep notes temporarily. So, I
can use an already installed chat service or email or SMS to send the
information to myself, and later delete it after capturing it in mind
.
But, mind
should remind me to visit the apps when I open it in my laptop
after a certain time.
I might be a nerd and use custom IOT devices to capture notes. So, I want to be able to implement a custom, self-hosted sync service.
I might not have an electronic device at all, and use a plain old physical
notebook or even my palms to capture information. So, I want to get reminded
to go through my notebooks and hands when I open mind
after some time.
I might want to sync from my X app/service automatically, but not sure how. So, I want to have some easy way to ask the community.
I might want to sync from different projects in different places in my filesystem. So, I want mind
to be able to crrate different projects and auto add tasks from the subprojects.
The preferred method of sync/communication will be using websocket because it has to be real-time.
The information will be captured (queued) as .txt
files in a specific directory like /.mind/inbasket
, waiting to be processed in the next step. To add some new information to the queue, go to the inbasket directory and enter vim info-$(date -u "+%s").txt
.
Once I capture enough information that might have some meaning for me, when I get some free time, I want to go through them and analyze what they really are.
I can delete the information that has no meaning for me. Others are actionable.
For each actionable item, if it's something trivial, I need to finish it right away. Else, I need to convert them to "Task"s.
I need to prepare well so that I can skip the turning into task step for as many items as possible.
The tasks could be stored as task-$(date -u "+%s").yml
files in the ~/.mind/tasks
directory.
The UI will display the information one by one, each for max 2 minutes. I can either finish it right then or turn it into a "Task".
In any case, I need to mark it as "Done" before the timeout, else it will get re-stacked and the next item will appear.
In order to turn some information into a "Task" I need to define the following:
The information should get auto-attached to the task.
There will be customizable shortcuts to perform actions like making API calls, auto generate tasks etc.
When the in basket is empty, it will remind me to check other sources like mobile, notebook etc. whatever I have defined as my in-basket, and provide me an interface to add adhoc tasks.
Once I know what to do and how to do, I need to decide if I should and when to do it. Basically, I need to put the tasks in different baskets. For e.g.
These can be actual folders inside ~/.mind/tasks
.
A bunch of folders. Some will be there by default but can be deleted. Others
can be created. The folders can be ordered by using a prefix numbers. Tasks
can be dragged and dropped from one folder to another folder easily. No sub
folders will be supported. Each folder can contain meta configuration as a
config.yml
file inside them. The meta configuration can define properties
like color, tags etc.
This is where tasks get priorities based on the 6 horizons of focus:
The horizons can be defined in different folders like
~/.mind/horizons_of_focus/${num}-${title}
.
This step requires maximum visibility to all the tasks that need to be done. It's basically a dashboard where I can zoom in and zoom out into different horizons. Every horizon will have a priority set by me. Each item in every horizon will have a priority set. The dashboard will allow me to define how critical is the task for each item in each horizon. Then, I'll get the final priority calculated by an algorithm, also defined by me. Ofcource, I can add bias points to the task depending on my mood.
Now that the priorities are defined, it's time to engage and start doing. At this point I'm sure that whatever I'm doing is the best things I could be doing right now. There's no pending task or might-be-critical information hiding in my mind and making me anxious. All I need is the list of tasks to be done.
This is a list of TODOs auto arranged by the calculated priority. All I need to do is, finish each task and tick it off from the list.
Let's iterate on the design and try looking from another angle.
What if we generalise the process and make it implementation independent?
I think we can reduce the whole thing into a simple concept of a version controlled information-label system.
Let's see how.
The core is the storage that stores information, labels, properties and revisions, as simple as that.
So, at minimum the core exposes api to:
Information is something we capture, often not knowing what it really is, or what exactly to do with it. It's just some text data with mime type and revision. After capturing we will update it, attach and detach labels and properties, until we have dealt with it and are ready to delete it. That's all the core allows us to do with it.
As per the core, labels are unique entities (defined as string
). The core
doesn't know what or how many labels are there, what they look like or what
they mean. It can only attach and detach labels to information from the given
string.
A property is also something that can be attached to an information. But unlike labels, which carry only 2 possible states (attached/detached), properties allow us to attach extra metadata as key-value pairs.
Each change to the information will contain a revision (basically a UTC timestamp), so that sync works. Deleted information will have only the id and revision fields remaining in the DB.
That's all the core does, i.e. store data. The actual logic will be implemented by the platform and the user.
A platform lets the user interact with the storage. But it does a lot more than that.
The platform knows the format of the information. It also formats the information before storing. The platform gets to decide what types of data it will support, and what to do with unsupported data.
The platform can define what some labels and properties mean, how they behave and how they look like. Based on the type of information and the labels and properties attached to it, the platform can define how to display them and how users interact with them.
For e.g. A platform can define a label called Pinned
, and tell the users
that any information with this label attached will be displayed at the top of
the page with a pin symbol. Or define a property called reminder
and tell the
user that information with this property set will behave like a reminder.
Platforms can also let the users define custom labels and properties, and define how they look and behave.
The platform can utilise the revision fields to sync data between multiple devices.
The platform takes most of the responsibility to allow interaction between the user and the storage.
The platform can also define or allow the users to define what happens when some event occurs (e.g. new information, assigned a certain label, deleted a property) etc.
The platform can also implement support for calender, project management tools and frameworks etc. but these are not requirements.
The only requirements expected from a platform is to utilise the core storage system and define everything in terms of information, labels and properties (except uploaded files if any). And also to standardize the platform specific meanings of labels and properties so that migration between platforms are possible without going beyond what the core system allows.
Depending on what the platform enables, the user can also utilize the system to organize and automate organization steps using the platform supported scripting (code or nocode).
However, it'd be great if the platform allows the users to collaborate and share their labels, properties and automation scripts to help each other out, and the users actually do so. Not required, but highly recommended.
Benefits of the setting explained above:
Drawback:
Most are related.
Example storage using plain files and folders (git optimized):
/wrksp1/information/123/rev1/data /wrksp1/information/123/rev1/labels/label1 /wrksp1/information/123/rev1/properties/prop1
The simplest way is to dump everything in a yaml file like mind already does.
A label should confirm to the format: definition::label-parent:label-child
.
e.g. plt::pinned
, plt::reminder:repeating
, plt::pinned:sidebar
, usr::work
.
The definition::
part denotes where the meaning of the label is defined. Is it defined by the platform (plt::
)? Or is it defined by the user (usr::
)? If no definition is provided, it will default to usr::
.
Now, the actual label can be defined using lower-case, hyphen (-
) separated words. Nested labels can be defined using a colon (:
) separator.
Similar to labels, properties also confirm to the definition::property-parent:property-child
format and follows the same logic.
This separation of platform and user defined labels is necessary to avoid conflict, where the user means one thing and the platform understands another. For e.g. the word wip
might mean that the task is "work in progress" to the platform, but might also mean it's a "wise individual's principle" (something I made up) to the user. Both shouldn't be mixed up.
This also makes it easy to migrate from one platform to another without losing functionality, because it will be easy for the migration tools to rename the plt::
labels to the destination platform's equivalent platform defined labels to keep the functionality intact.
We could also introduce std::
to define a standard set of labels that every platform should support, but I think that might be asking too much of the platforms. Also, there will be extra headache to support different versions of the standard.
A better alternative would be to introduce cmm::{community}::{user}::label
, where {community}
is the name/domain of a community and {user}
is the user ID of a member in the community who contributed the meaning of the label. It'd be up to the platforms to support community contributed labels.
Write a design for the possible solution we came up with in #49.
Ref: #46