Welcome to Comodoro CLI, the Command-Line Interface to manage your personal time based on time-lib.

Features

  • Centralized server timer controllable by multiple clients at the same time
  • Multi protocols (only TCP for now, but you can build your own)
  • Cycles customizable via config file (Pomodoro style, 52/17 style, custom)
  • Server and timer hooks customizable via config file
  • …and more!

Installation

# Cargo
$ cargo install comodoro

# Nix
$ nix-env -i comodoro

See the documentation for other installation methods.

Configuration

Please read the documentation.

Contributing

Please read the contributing guide for more detailed information.

A bug tracker is available on SourceHut. [send an email]

A mailing list is available on SourceHut. [send an email] [subscribe] [unsubscribe]

If you want to report a bug, please send an email at ~soywod/pimalaya@todo.sr.ht.

If you want to propose a feature or fix a bug, please send a patch at ~soywod/pimalaya@lists.sr.ht. The simplest way to send a patch is to use git send-email, follow this guide to configure git properly.

If you just want to discuss about the project, feel free to join the Matrix workspace #pimalaya.comodoro or contact me directly @soywod. You can also use the mailing list.

Sponsoring

nlnet

Special thanks to the NLnet foundation and the European Commission that helped the project to receive financial support from:

If you appreciate the project, feel free to donate using one of the following providers:

GitHub Sponsors, PayPal, Ko-fi, Buy Me a Coffee, Liberapay

Installation

Cargo

Comodoro can be installed with cargo:

$ cargo install comodoro

You can also use the git repository for a more up-to-date (but less stable) version:

$ cargo install --git https://github.com/soywod/comodoro comodoro

Comodoro comes with few features:

  • client: enable the timer subcommand to manage timers
  • server: enable the server subcommand to manage servers
  • tcp-client: enable the TCP client
  • tcp-binder: enable the TCP binder for the server
  • hook-command: enable hook based on shell commands
  • hook-notify: enable hooks based on system notifications

By choosing features you need, you can build a smaller executable. For example, if you only need the tcp-binder with hook-notify, you can run this command:

$ cargo install --no-default-features --features tcp-binder --features hook-notify comodoro

Nix

Comodoro can be installed with Nix:

nix-env -i comodoro

You can also use the git repository for a more up-to-date (but less stable) version:

nix-env -if https://github.com/soywod/comodoro/archive/master.tar.gz
# or, from within the source tree checkout
nix-env -if .

If you have the Flakes feature enabled:

nix profile install comodoro
# or, from within the source tree checkout
nix profile install

# you can also run Comodoro directly without installing it:
nix run comodoro

Development environment

To enter a development shell:

nix-shell
# or, with the Flakes feature enabled
nix develop

From here, you have access to all the development tools (Rust compiler, cargo, rust language server, code formatter…) necessary to hack on Comodoro.

Binary

Comodoro can be installed with a prebuilt binary:

# As root:
curl -sSL https://pimalaya.org/comodoro/cli/install.sh | sudo sh

# As a regular user:
curl -sSL https://pimalaya.org/comodoro/cli/install.sh | PREFIX=~/.local sh

Those commands install the latest binary from the GitHub releases section.

Note: Linux, macOS and Windows are supported. Note that some features may not work as expected on Windows.

Sources

Comodoro can be installed from sources.

First you need to install the Rust development environment (see the rust installation documentation):

curl https://sh.rustup.rs -sSf | sh

Then, you need to clone the repository and install dependencies:

git clone https://github.com/soywod/comodoro.git
cd comodoro
cargo check

Now, you can build Comodoro:

cargo build --release

Note: binaries are available in the target/release folder.

Configuration

Comodoro takes its TOML configuration from one of those paths:

  • $XDG_CONFIG_HOME/comodoro/config.toml
  • $HOME/.config/comodoro/config.toml
  • $HOME/.comodororc

The file should contain presets. A preset is a set of configuration gathered under a unique name, in a TOML table. Each set of configuration can be splitted into 3 categories:

[presets.a]
# config A here

[presets.b]
# config B here

# …

Example

Here a complete and documented config.sample.toml that you can actually test yourself with the following commands:

# start the server using TCP
$ comodoro server start example tcp

# in an other prompt, start the timer
$ comodoro timer start example tcp
# A preset is a set of configuration identified by a name.
[presets.example]

# TCP configuration, used by server binders and by clients.
# Requires the cargo feature "tcp".
tcp.host = "localhost"
tcp.port = 1234

# A cycle is a step in the timer lifetime, represented by a name and a
# duration. You can either define custom cycles:
cycles = [
  { name = "Work", duration = 5 },
  { name = "Rest", duration = 3 },
]

# Predefined cycles can also be used:
# preset = "pomodoro" | "52/17"

# Force the timer to stop after the given amount of loops:
# cycles-count = 5

# Customize the timer precision. Available options: second, minute, hour.
# timer-precision = "minute"

# A hook can be either a shell command or a system notification. Hook
# names follow the format "on-{name}-{event}", where "name" is the
# kebab-case version of the cycle name, and "event" the type of event:
# begin, running, set, pause, resume, end.
hooks.on-work-begin.notify.summary = "Comodoro"
hooks.on-work-begin.notify.body = "Work started!"
# hooks.on-work-begin.cmd = "notify-send Comodoro 'Work started!'"

Cycles configuration

A cycle is a step in the timer lifetime, represented by a name and a duration.

You can setup custom cycles using the cycles TOML array of tables:

[presets.example]

[[presets.example.cycles]]
name = "Work"
duration = 1500

[[presets.example.cycles]]
name = "Rest"
duration = 500

Inline array also works:

[presets.example]

cycles = [
  { name = "Work", duration = 1500 },
  { name = "Rest", duration = 500 },
]

cycles-count

By default, cycles will repeat indefinitely. The number of loops can be fixed this way:

[presets.example]
cycles-count = 5

Note: a cycles count at 0 means infinite loops.

preset = "pomodoro"

Configure cycles to follow the Pomodoro time management method, which consists of alternating "Work" cycles of 25 min and "Short break" cycles of 5 min, 4 times, then ending by a "Long break" of 15 min.

[presets.example]
preset = "pomodoro"

preset = "52/17"

Configure cycles to follow the 52/17 time management method, which consists of alternating "Work" cycles of 52 min and "Resting" cycles of 17 min.

[presets.example]
preset = "52/17"

Hooks configuration

Hooks allow you to execute actions during the server and the timer lifecycles. There is 2 possible type of actions:

  • Execute a shell command (requires the hook-command cargo feature).
  • Send a system notification (requires the hook-notify cargo feature).

A hook follows the pattern on-{target}-{event}, where the target is either server, timer or the kebab-case version of the current cycle’s name.

on-{target}-{event}.cmd

Execute the given shell command when the given event is emitted.

[presets.example]
hooks.on-timer-start.cmd = "task start"

on-{target}-{event}.notify

Send the given system notification when the given event is emitted.

[presets.example]
hooks.on-timer-start.notify.summary = "Comodoro"
hooks.on-timer-start.notify.body = "Timer started!"

Server hooks

  • on-server-start, when the server starts

  • on-server-stopping, when the server received the order to stop

  • on-server-stop, when the server stops

Timer hooks

  • on-timer-start, when the timer starts

  • on-timer-stop, when the timer stops

You also have access to cycle-specific hooks, where {name} is the kebab-case version of your custom cycle’s name:

  • on-{name}-begin, when the cycle begins

  • on-{name}-running, when cycle runs (tick)

  • on-{name}-set, when the cycle duration is manually changed

  • on-{name}-pause, when the cycle is paused

  • on-{name}-resume, when the cycle is resumed

  • on-{name}-end, when the cycle ends

Protocols configuration

List of protocols supported by the CLI:

TCP configuration

tcp.host

Host name used by the server to listen for connections and by the client to connect to the server.

tcp.port

Port used by the server to listen for connections and by the client to connect to the server.

Usage

$ comodoro [OPTIONS] <COMMAND>

Options

These options are global, which means they can be used in all commands and subcommands.

-c|--config

Overrides the default configuration file path.

This option takes a path as an argument. The path is shell expanded, which means it can contain ~ and environment variables.

Server

$ comodoro server [OPTIONS] <COMMAND>

Server commands are prefixed by the command server. The server can be managed with those commands:

Start the server

$ comodoro server start [OPTIONS] <PRESET> [PROTOCOL]...

Starts the server and blocks the current thread. Requires a preset name and at least one protocol in order to accept connections.

Client

$ comodoro timer [OPTIONS] <COMMAND>

Client commands are prefixed by the command timer. The timer can be managed with those commands:

Start the timer

$ comodoro timer start [OPTIONS] <PRESET> <PROTOCOL>

Starts the timer using the given preset name and protocol.

Get the timer

$ comodoro timer start [OPTIONS] <PRESET> <PROTOCOL>

Gets the current timer using the given preset name and protocol. Depending on the state, the timer has the following format:

Stopped

OFF

Paused

[<cycle-name>] paused

Running if timer >= 60

[<cycle-name>] <time>min

Running if timer < 60

[<cycle-name>] <time>s

Pause the timer

$ comodoro timer start [OPTIONS] <PRESET> <PROTOCOL>

Pauses the timer using the given preset name and protocol.

Resume the timer

$ comodoro timer start [OPTIONS] <PRESET> <PROTOCOL>

Resumes the timer using the given preset and protocol.

Stop the timer

$ comodoro timer start [OPTIONS] <PRESET> <PROTOCOL>

Stops the timer using the given preset name and protocol.