### Overview # Overview `jrnl` is a simple journal application for the command line. You can use it to easily create, search, and view journal entries. Journals are stored as human-readable plain text, and can also be encrypted using [AES encryption](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard). `jrnl` has most of the features you need, and few of the ones you don't. ## Plain Text `jrnl` stores each journal in plain text. You can store `jrnl` files anywhere, including in shared folders to keep them synchronized between devices. Journal files are compact (thousands of entries take up less than 1 MiB) and can be read by almost any electronic device, now and for the foreseeable future. ## Tags To make it easier to find entries later, `jrnl` includes support for inline tags (the default tag symbol is `@`). You can find and filter entries by using tags along with other search criteria. ## Support for Multiple Journals `jrnl` includes support for the creation of multiple journals, each of which can be stored as a single file or as a set of files. Entries are automatically timestamped in a human-readable format that makes it easy to view multiple entries at a time. `jrnl` can easily find the entries you want so that you can read them or edit them. ## Support for External Editors `jrnl` plays nicely with your favorite text editor. You may prefer to write journal entries in an editor. Or you may want to make changes that require a more comprehensive application. `jrnl` can filter specific entries and pass them to the [external editor](./external-editors.md) of your choice. ## Encryption `jrnl` includes support for [AES encryption](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard). See the [encryption page](./encryption.md) for more information. ## Import and Export `jrnl` makes it easy to import entries from other sources. Existing entries can be exported in a variety of [formats](./formats.md). ## Multi-Platform Support `jrnl` is compatible with most operating systems. You can [download](./installation.md) it using one of a variety of package managers, or you can build from source. ## Open-Source `jrnl` is written in [Python](https://www.python.org) and maintained by a [friendly community](https://github.com/jrnl-org/jrnl) of open-source software enthusiasts. --- ### Advanced # Advanced Usage ## Configuration File `jrnl` has a wide variety of options that can be customized through the config file, including templates, formats, multiple journals, and more. See the [configuration file reference](./reference-config-file.md) for details or read on for some common use cases. ### Multiple journal files You can configure `jrnl`to use with multiple journals (eg. `private` and `work`) by defining more journals in your [config file](./reference-config-file.md), for example: ``` yaml journals: default: ~/journal.txt work: ~/work.txt ``` The `default` journal gets created the first time you start `jrnl` Now you can access the `work` journal by using `jrnl work` instead of `jrnl`, eg. ``` sh jrnl work at 10am: Meeting with @Steve jrnl work -n 3 ``` will both use `~/work.txt`, while `jrnl -n 3` will display the last three entries from `~/journal.txt` (and so does `jrnl default -n 3`). You can also override the default options for each individual journal. If your `jrnl.yaml` looks like this: ``` yaml encrypt: false journals: default: ~/journal.txt work: journal: ~/work.txt encrypt: true food: ~/my_recipes.txt ``` Your `default` and your `food` journals won't be encrypted, however your `work` journal will! You can override all options that are present at the top level of `jrnl.yaml`, just make sure that at the very least you specify a `journal: ...` key that points to the journal file of that journal. Consider the following example configuration ``` yaml editor: vi -c startinsert journals: default: ~/journal.txt work: journal: ~/work.txt encrypt: true display_format: json editor: code -rw food: display_format: markdown journal: ~/recipes.txt ``` The `work` journal is encrypted, prints to `json` by default, and is edited using an existing window of VSCode. Similarly, the `food` journal prints to markdown by default, but uses all the other defaults. ### Modifying Configurations from the Command line You can override a configuration field for the current instance of `jrnl` using `--config-override CONFIG_KEY CONFIG_VALUE` where `CONFIG_KEY` is a valid configuration field, specified in dot notation and `CONFIG_VALUE` is the (valid) desired override value. The dot notation can be used to change config keys within other keys, such as `colors.title` for the `title` key within the `colors` key. You can specify multiple overrides as multiple calls to `--config-override`. !!! note These overrides allow you to modify ***any*** field of your jrnl configuration. We trust that you know what you are doing. #### Examples: ``` sh # Create an entry using the `stdin` prompt, for rapid logging jrnl --config-override editor "" # Populate a project's log jrnl --config-override journals.todo "$(git rev-parse --show-toplevel)/todo.txt" todo find my towel # Pass multiple overrides jrnl --config-override display_format fancy --config-override linewrap 20 \ --config-override colors.title green ``` ### Using an alternate config You can specify an alternate configuration file for the current instance of `jrnl` using `--config-file CONFIG_FILE_PATH` where `CONFIG_FILE_PATH` is a path to an alternate `jrnl` configuration file. #### Examples: ``` sh # Use personalised configuration file for personal journal entries jrnl --config-file ~/foo/jrnl/personal-config.yaml # Use alternate configuration file for work-related entries jrnl --config-file ~/foo/jrnl/work-config.yaml # Use default configuration file (created on first run) jrnl ``` --- ### Contributing # Contributing to jrnl We welcome contributions to jrnl, whether it's through reporting bugs, improving the documentation, testing releases, engaging in discussion on features and bugs, or writing code. ## Table of Contents * [Code of Conduct](#code-of-conduct) * [Reporting Bugs](#reporting-bugs) * [Editing Documentation](#editing-documentation) * [Testing](#testing) * [Submitting feature requests and ideas](#submitting-feature-requests-and-ideas) * [Developing jrnl](#developing) ## Code of Conduct Before starting, please read the [Code of Conduct](https://github.com/jrnl-org/jrnl/blob/main/CODE_OF_CONDUCT.md). ## Reporting Bugs Please report bugs by [opening a new issue](https://github.com/jrnl-org/jrnl/issues/new/choose) and describing it as well as possible. Many bugs are specific to a particular operating system and Python version, so please include that information! ## Editing Documentation If you find a typo or a mistake in the docs, please fix it right away and send a pull request. If you're unsure what to change but still see a problem, you can [open a new issue](https://github.com/jrnl-org/jrnl/issues/new/choose) with the "Documentation change" type. To edit the documentation, edit the `docs/*.md` files on the **main** branch. You can see the result by running `poe docs-run` inside the project's root directory, then navigating your browser to [localhost:8000](http://localhost:8000). ### External editors and tips and tricks If you'd like to share a jrnl command line trick that you find useful, you may find it worthwhile to add it to the ["Tips and Tricks" section](tips-and-tricks.md). For advice on how to integrate a particular external editor, you can add to the ["External Editors" section](external-editors.md). ## Testing Much of the work of maintaining jrnl involves testing rather than coding. The nature of jrnl means we deal with extremely sensitive data, and can't risk data loss. While jrnl does have a comprehensive automated testing suite, user testing is crucial to mitigating this risk. ### Prereleases [Prereleases are deployed through PyPi much like normal releases](https://pypi.org/project/jrnl/#history). You can use [pipx](https://pypi.org/project/pipx/) to fetch them and test them. See the [changelog](https://github.com/jrnl-org/jrnl/blob/main/CHANGELOG.md) for information on what has changed with each release. ### Pull requests If you are comfortable enough with git, feel free to fetch particular [pull requests](https://github.com/jrnl-org/jrnl/pulls), test them yourself, and report back your findings. Bonus points if you can add a screencast of how the new feature works. ### Confirm bug reports There are always [open bugs among our GitHub issues](https://github.com/jrnl-org/jrnl/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and many are specific to a particular OS, Python version, or jrnl version. A simple comment like "Confirmed on jrnl v2.2, MacOS 10.15, Python 3.8.1" would be extremely helpful in tracking down bugs. ### Automate tests See the develop section below for information on how to contribute new automated tests. ## Submitting feature requests and ideas If you have a feature request or idea for jrnl, please [open a new issue](https://github.com/jrnl-org/jrnl/issues/new/choose) and describe the goal of the feature, and any relevant use cases. We'll discuss the issue with you, and decide if it's a good fit for the project. When discussing new features, please keep in mind our design goals. jrnl strives to [do one thing well](https://en.wikipedia.org/wiki/Unix_philosophy). To us, that means: * being _nimble_ * having a simple interface * avoiding duplicating functionality ## Developing ### Getting your environment set up You will need to install [poetry](https://python-poetry.org/) to develop jrnl. It will take care of all of the project's other dependencies. ### Understanding the branches jrnl uses two primary branches: * `main` - for ongoing development * `release` - for releases In general, pull requests should be made on the `main` branch. #### Updating an existing clone after the `develop` → `main` rename If you have a clone from before the default branch was renamed from `develop` to `main`, update it with: ```bash git checkout develop git branch -m develop main git fetch origin git remote prune origin git branch -u origin/main main git remote set-head origin -a ``` If you have other local branches based on `develop`, rebase them onto `main`: ```bash git rebase --onto main develop ``` ### Common development commands You can find an inventory of commands in the `pyproject.toml`. Users can run the commands by typing `poe` followed by the name of the command ([Poe the Poet](https://github.com/nat-n/poethepoet) can be installed on its own, or as part of `poetry install`). A typical development workflow includes: * Installing dependencies: * `poetry install` * Activate virtual environment: * `poetry shell` * Running the source in a virtual environment: * `jrnl` (with or without arguments as necessary) * Running tests: * `poe test` * Formatting the code to standardize its style: * `poe format` ### Updating automated tests When resolving bugs or adding new functionality, please add tests to prevent that functionality from breaking in the future. If you notice any functionality that isn't covered in the tests, feel free to submit a test-only pull request as well. For testing, jrnl uses [pytest](https://docs.pytest.org) for unit tests, and [pytest-bdd](https://pytest-bdd.readthedocs.io/) for integration testing. All tests are in the `tests` folder. Many tests can be created by only editing `*.feature` files with the same format as other tests. For more complicated functionality, you may need to implement steps in `tests/lib/` which are then executed by your tests in the `feature` files. ### Submitting pull requests When you're ready, feel free to submit a pull request (PR). The jrnl maintainers generally review the pull requests every two weeks, but the continuous integration pipeline will run on automated tests on it within a matter of minutes and will report back any issues it has found with your code across a variety of environments. The pull request template contains a checklist full of housekeeping items. Please fill them out as necessary when you submit. If a pull request contains failing tests, it probably will not be reviewed, and it definitely will not be approved. However, if you need help resolving a failing test, please mention that in your PR. ### Finding things to work on You can search the [jrnl GitHub issues](https://github.com/jrnl-org/jrnl/issues) by [label](https://github.com/jrnl-org/jrnl/labels) for things to work on. Here are some labels worth searching: * [critical](https://github.com/jrnl-org/jrnl/labels/critical) * [help wanted](https://github.com/jrnl-org/jrnl/labels/help%20wanted) * [bug](https://github.com/jrnl-org/jrnl/labels/bug) * [enhancement](https://github.com/jrnl-org/jrnl/labels/enhancement) You can also get a feel for the project's priorities by reviewing the [milestones](https://github.com/jrnl-org/jrnl/milestones). ### A note for new programmers and programmers new to python Although jrnl has grown quite a bit since its inception, the overall complexity (for an end-user program) is fairly low, and we hope you'll find the code easy enough to understand. If you have a question, please don't hesitate to ask! Python is known for its welcoming community and openness to novice programmers, so feel free to fork the code and play around with it! If you create something you want to share with us, please create a pull request. We never expect pull requests to be perfect, idiomatic, instantly mergeable code. We can work through it together! --- ### Encryption # Encryption ## A Note on Security While `jrnl` follows best practices, total security is never possible in the real world. There are a number of ways that people can at least partially compromise your `jrnl` data. See the [Privacy and Security](./privacy-and-security.md) page for more information. There is one relevant security advisory for encryption-related security issues: [GHSA-rhx6-37mm-5q9r](https://github.com/jrnl-org/jrnl/security/advisories/GHSA-rhx6-37mm-5q9r). ## Encryption Behavior Overview - Encrypted journals are now written in the jrnl v3 format. - jrnl v1 and v2 encrypted files are read-only formats. They can still be opened and decrypted, but new encrypted writes are always v3. ## jrnl v3 Encrypted File Format jrnl v3 uses a random 16-byte salt per encrypted write, stored in a JSON header after a magic prefix. This avoids the static-salt weakness from v2. File layout: | Field | Size | Description | | --- | --- | --- | | `JRNLv3` | 6 bytes | Magic prefix | | `header_len` | 2 bytes (uint16 BE) | Length of the header field, max 64KB | | header | `header_len` bytes | Base64-encoded JSON, includes `salt` (base64url-encoded 16-byte salt) | | Fernet token | Remaining bytes | Ciphertext | Additional header fields may be added in future without changing the format version. !!! note Journals encrypted with v3 before this format was base64-encoded store raw JSON in the header field instead. These are still read correctly; the base64-encoded format is written on the next save. ## Encrypting and Decrypting from the CLI To encrypt a journal, run: ``` sh jrnl --encrypt [FILENAME] ``` You can then enter a new password, and the unencrypted file will replaced with the new encrypted file. This command also works to change the password for a journal file that is already encrypted. `jrnl` will prompt you for the current password and then new password. Conversely, run this to decrypt a journal: ``` sh jrnl --decrypt [FILENAME] ``` replaces the encrypted journal file with a plain text file. You can also specify a filename, e.g., `jrnl --decrypt plain_text_copy.txt`, to leave the original encrypted file untouched and create a new plain text file next to it. !!! note Changing `encrypt` in your [config file](./reference-config-file.md) to a different value will not encrypt or decrypt your journal file. It merely says whether or not your journal is encrypted. Hence manually changing this option will most likely result in your journal file being impossible to load. This is why the above commands are necessary. ## Storing Passwords in Your Keychain Nobody can recover or reset your `jrnl` password. If you lose it, your data will be inaccessible forever. For this reason, when encrypting a journal, `jrnl` asks whether you would like to store the password in your system's keychain. An added benefit is that you will not need to enter the password when interacting with the journal file. If you don't initially store the password in your keychain but decide to do so later---or if you want to store it in one computer's keychain but not in another computer's---you can run `jrnl --encrypt` on an encrypted journal and use the same password again. This will trigger the keychain storage prompt. ## Manual Decryption The easiest way to decrypt your journal is with `jrnl --decrypt`, but you could also decrypt your journal manually if needed. To do this, you can use any program that supports the AES algorithm (specifically AES-CBC), and you'll need the following relevant information for decryption: - **Key:** The key used for encryption is the [SHA-256](https://en.wikipedia.org/wiki/SHA-2) hash of your password. - **Initialization vector (IV):** The IV is stored in the first 16 bytes of your encrypted journal file. - **The actual text of the journal** (everything after the first 16 bytes in the encrypted journal file) is encoded in [UTF-8](https://en.wikipedia.org/wiki/UTF-8) and padded according to [PKCS\#7](https://en.wikipedia.org/wiki/PKCS_7) before being encrypted. If you'd like an example of what this might look like in script form, please see below for some examples of Python scripts that you could use to manually decrypt your journal. !!! note These are only examples, and are only here to illustrate that your journal files will still be recoverable even if `jrnl` isn't around anymore. Please use `jrnl --decrypt` if available. **Example for jrnl v2 files**: ``` python #!/usr/bin/env python3 """ Decrypt a jrnl v2 encrypted journal. Note: the `cryptography` module must be installed (you can do this with something like `pip3 install crytography`) """ import base64 import getpass from pathlib import Path from cryptography.fernet import Fernet from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC filepath = input("journal file path: ") password = getpass.getpass("Password: ") with open(Path(filepath), "rb") as f: ciphertext = f.read() password = password.encode("utf-8") kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=b"\xf2\xd5q\x0e\xc1\x8d.\xde\xdc\x8e6t\x89\x04\xce\xf8", iterations=100_000, backend=default_backend(), ) key = base64.urlsafe_b64encode(kdf.derive(password)) print(Fernet(key).decrypt(ciphertext).decode("utf-8")) ``` **Example for jrnl v1 files**: ``` python #!/usr/bin/env python3 """ Decrypt a jrnl v1 encrypted journal. Note: the `pycrypto` module must be installed (you can do this with something like `pip3 install pycrypto`) """ import argparse import getpass import hashlib from Crypto.Cipher import AES parser = argparse.ArgumentParser() parser.add_argument("filepath", help="journal file to decrypt") args = parser.parse_args() pwd = getpass.getpass() key = hashlib.sha256(pwd.encode("utf-8")).digest() with open(args.filepath, "rb") as f: ciphertext = f.read() crypto = AES.new(key, AES.MODE_CBC, ciphertext[:16]) plain = crypto.decrypt(ciphertext[16:]) plain = plain.strip(plain[-1:]) plain = plain.decode("utf-8") print(plain) ``` --- ### External Editors # External editors Configure your preferred external editor by updating the `editor` option in your [configuration file](./reference-config-file.md#editor). If your editor is not in your operating system's `PATH` environment variable, then you will have to enter the full path of your editor. Once it's configured, you can create an entry as a new document in your editor using the `jrnl` command by itself: ``` text jrnl ``` You can specify the time and title of the entry as usual on the first line of the document. If you want, you can skip the editor by including a quick entry with the `jrnl` command: ``` text jrnl yesterday: All my troubles seemed so far away. ``` If you want to start the entry on the command line and continue writing in your chosen editor, use the `--edit` flag. For example: ``` text jrnl yesterday: All my troubles seemed so far away. --edit ``` !!! note To save and log any entry edits, save and close the file. All editors must be [blocking processes](https://en.wikipedia.org/wiki/Blocking_(computing)) to work with jrnl. Some editors, such as [micro](https://micro-editor.github.io/), are blocking by default, though others can be made to block with additional arguments, such as many of those documented below. If jrnl opens your editor but finishes running immediately, then your editor is not a blocking process, and you may be able to correct that with one of the suggestions below. Please see [this section](./privacy-and-security.md#editor-history) about how your editor might leak sensitive information and how to mitigate that risk. ## Sublime Text To use [Sublime Text](https://www.sublimetext.com/), install the command line tools for Sublime Text and configure your `jrnl.yaml` like this: ```yaml editor: "subl -w" ``` Note the `-w` flag to make sure `jrnl` waits for Sublime Text to close the file before writing into the journal. ## Visual Studio Code [Visual Studio Code](https://code.visualstudio.com) also requires a flag that tells the process to wait until the file is closed before exiting: ```yaml editor: "code --wait" ``` On Windows, `code` is not added to the path by default, so you'll need to enter the full path to your `code.exe` file, or add it to the `PATH` variable. ## MacVim Also similar to Sublime Text, MacVim must be started with a flag that tells the the process to wait until the file is closed before passing control back to journal. In the case of MacVim, this is `-f`: ```yaml editor: "mvim -f" ``` ## Vim/Neovim To use any of the Vim derivatives as editor in Linux, simply set the `editor` to the executable: ```yaml editor: "vim" # or editor: "nvim" ``` ## iA Writer On OS X, you can use the fabulous [iA Writer](http://www.iawriter.com/mac) to write entries. Configure your `jrnl.yaml` like this: ```yaml editor: "open -b pro.writer.mac -Wn" ``` What does this do? `open -b ...` opens a file using the application identified by the bundle identifier (a unique string for every app out there). `-Wn` tells the application to wait until it's closed before passing back control, and to use a new instance of the application. If the `pro.writer.mac` bundle identifier is not found on your system, you can find the right string to use by inspecting iA Writer's `Info.plist` file in your shell: ```sh grep -A 1 CFBundleIdentifier /Applications/iA\ Writer.app/Contents/Info.plist ``` ## Notepad++ on Windows To set [Notepad++](http://notepad-plus-plus.org/) as your editor, edit the `jrnl` config file (`jrnl.yaml`) like this: ```yaml editor: "C:\\Program Files (x86)\\Notepad++\\notepad++.exe -multiInst -nosession" ``` The double backslashes are needed so `jrnl` can read the file path correctly. The `-multiInst -nosession` options will cause `jrnl` to open its own Notepad++ window. ## emacs To use `emacs` as your editor, edit the `jrnl` config file (`jrnl.yaml`) like this: ```yaml editor: emacsclient -a "" -c ``` When you're done editing the message, save and `C-x #` to close the buffer and stop the emacsclient process. ## gedit To use [gedit](https://gedit-text-editor.org/) as your editor, edit the `jrnl` config file (`jrnl.yaml`) like this: ```yaml editor: "gedit -w" ``` The `-w` (`--wait`) flag tells `gedit` to wait until the file is closed before passing control back to `jrnl`. ## Other editors If you're using another editor and would like to share, feel free to [contribute documentation](./contributing.md#editing-documentation) on it. --- ### Formats # Formats `jrnl` supports a variety of alternate formats. These can be used to display your journal in a different manner than the `jrnl` default, and can even be used to pipe data from your journal for use in another program to create reports, or do whatever you want with your `jrnl` data. Any of these formats can be used with a search (e.g. `jrnl -contains "lorem ipsum" --format json`) to display the results of that search in the given format, or can be used alone (e.g. `jrnl --format json`) to display all entries from the selected journal. This page shows examples of all the built-in formats, but since `jrnl` supports adding more formats through plugins, you may have more available on your system. Please see `jrnl --help` for a list of which formats are available on your system. Any of these formats can be used interchangeably, and are only grouped into "display", "data", and "report" formats below for convenience. ## Display Formats These formats are mainly intended for displaying your journal in the terminal. Even so, they can still be used in the same way as any other format (like written to a file, if you choose). ### Pretty ``` sh jrnl --format pretty # or jrnl -1 # any search ``` This is the default format in `jrnl`. If no `--format` is given, `pretty` will be used. It displays the timestamp of each entry formatted to by the user config followed by the title on the same line. Then the body of the entry is shown below. This format is configurable through these values from your config file (see [Advanced Usage](./advanced.md) for more details): - `colors` - `body` - `date` - `tags` - `title` - `indent_character` - `linewrap` - `timeformat` **Example output**: ``` sh 2020-06-28 18:22 This is the first sample entry | This is the sample body text of the first sample entry. 2020-07-01 20:00 This is the second sample entry | This is the sample body text of the second sample entry, but | this one has a @tag. 2020-07-02 09:00 This is the third sample entry | This is the sample body text of the third sample entry. ``` ### Short ``` sh jrnl --format short # or jrnl --short ``` This will shorten entries to display only the date and title. It is essentially the `pretty` format but without the body of each entry. This can be useful if you have long journal entries and only want to see a list of entries that match your search. **Example output**: ``` sh 2020-06-28 18:22 This is the first sample entry 2020-07-01 20:00 This is the second sample entry 2020-07-02 09:00 This is the third sample entry ``` ### Fancy (or Boxed) ``` sh jrnl --format fancy # or jrnl --format boxed ``` This format outlines each entry with a border. This makes it much easier to tell where each entry starts and ends. It's an example of how free-form the formats can be, and also just looks kinda ~*~fancy~*~, if you're into that kind of thing. **Example output**: ``` sh ┎──────────────────────────────────────────────────────────────────────╮2020-06-28 18:22 ┃ This is the first sample entry ╘═══════════════╕ ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ ┃ This is the sample body text of the first sample entry. │ ┖──────────────────────────────────────────────────────────────────────────────────────┘ ┎──────────────────────────────────────────────────────────────────────╮2020-07-01 20:00 ┃ This is the second sample entry ╘═══════════════╕ ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ ┃ This is the sample body text of the second sample entry, but this one has a @tag. │ ┖──────────────────────────────────────────────────────────────────────────────────────┘ ┎──────────────────────────────────────────────────────────────────────╮2020-07-02 09:00 ┃ This is the third sample entry ╘═══════════════╕ ┠╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤ ┃ This is the sample body text of the third sample entry. │ ┖──────────────────────────────────────────────────────────────────────────────────────┘ ``` ## Data Formats These formats are mainly intended for piping or exporting your journal to other programs. Even so, they can still be used in the same way as any other format (like written to a file, or displayed in your terminal, if you want). !!! note You may see boxed messages like "2 entries found" when using these formats, but those messages are written to `stderr` instead of `stdout`, and won't be piped when using the `|` operator. ### JSON ``` sh jrnl --format json ``` JSON is a very handy format used by many programs and has support in nearly every programming language. There are many things you could do with JSON data. Maybe you could use `jq` ([project page](https://github.com/stedolan/jq)) to filter through the fields in your journal. Like this: ``` sh $ j -3 --format json | jq '.entries[].date' jrnl-GFqVlfgP-py3.8  "2020-06-28" "2020-07-01" "2020-07-02" ``` Or why not create a [beautiful timeline](http://timeline.knightlab.com/) of your journal? **Example output**: ``` json { "tags": { "@tag": 1 }, "entries": [ { "title": "This is the first sample entry", "body": "This is the sample body text of the first sample entry.", "date": "2020-06-28", "time": "18:22", "tags": [], "starred": false }, { "title": "This is the second sample entry", "body": "This is the sample body text of the second sample entry, but this one has a @tag.", "date": "2020-07-01", "time": "20:00", "tags": [ "@tag" ], "starred": false }, { "title": "This is the third sample entry", "body": "This is the sample body text of the third sample entry.", "date": "2020-07-02", "time": "09:00", "tags": [], "starred": false } ] } ``` ### Markdown ``` sh jrnl --format markdown # or jrnl --format md ``` Markdown is a simple markup language that is human readable and can be used to be rendered to other formats (html, pdf). `jrnl`'s [README](https://github.com/jrnl-org/jrnl/blob/main/README.md) for example is formatted in markdown, then Github adds some formatting to make it look nice. The markdown format groups entries by date (first by year, then by month), and adds header markings as needed (e.g. `#`, `##`, etc). If you already have markdown header markings in your journal, they will be incremented as necessary to make them fit under these new headers (i.e. `#` will become `##`). This format can be very useful, for example, to export a journal to a program that converts markdown to html to make a website or a blog from your journal. **Example output**: ``` markdown # 2020 ## June ### 2020-06-28 18:22 This is the first sample entry This is the sample body text of the first sample entry. ## July ### 2020-07-01 20:00 This is the second sample entry This is the sample body text of the second sample entry, but this one has a @tag. ### 2020-07-02 09:00 This is the third sample entry This is the sample body text of the third sample entry. ``` ### Plain Text ``` sh jrnl --format text # or jrnl --format txt ``` This outputs your journal in the same plain-text format that `jrnl` uses to store your journal on disk. This format is particularly useful for importing and exporting journals within `jrnl`. You can use it, for example, to move entries from one journal to another, or to create a new journal with search results from another journal. **Example output**: ``` sh [2020-06-28 18:22] This is the first sample entry This is the sample body text of the first sample entry. [2020-07-01 20:00] This is the second sample entry This is the sample body text of the second sample entry, but this one has a @tag. [2020-07-02 09:00] This is the third sample entry This is the sample body text of the third sample entry. ``` ### XML ``` sh jrnl --format xml ``` This outputs your journal into XML format. XML is a commonly used data format and is supported by many programs and programming languages. **Example output**: ``` xml This is the first sample entry This is the sample body text of the first sample entry. This is the second sample entry This is the sample body text of the second sample entry, but this one has a @tag. *This is the third sample entry, and is starred This is the sample body text of the third sample entry. 1 ``` ### YAML ``` sh jrnl --format yaml --file 'my_directory/' ``` This outputs your journal into YAML format. YAML is a commonly used data format and is supported by many programs and programming languages. [Exporting to directories](#exporting-to-directories) is the only supported YAML export option and each entry will be written to a separate file. **Example file**: ``` yaml title: This is the second sample entry date: 2020-07-01 20:00 starred: False tags: tag This is the sample body text of the second sample entry, but this one has a @tag. ``` ## Report formats Since formats use your journal data and display it in different ways, they can also be used to create reports. ### Tags ``` sh jrnl --format tags # or jrnl --tags ``` This format is a simple example of how formats can be used to create reports. It displays each tag, and a count of how many entries in which tag appears in your journal (or in the search results), sorted by most frequent. Example output: ``` sh @one : 32 @two : 17 @three : 4 ``` ## Options ### Exporting with `--file` Example: `jrnl --format json --file /some/path/to/a/file.txt` By default, `jrnl` will output entries to your terminal. But if you provide `--file` along with a filename, the same output that would have been to your terminal will be written to the file instead. This is the same as piping the output to a file. So, in bash for example, the following two statements are equivalent: ``` sh jrnl --format json --file myjournal.json ``` ``` sh jrnl --format json > myjournal.json ``` #### Exporting to directories If the `--file` argument is a directory, jrnl will export each entry into an individual file: ``` sh jrnl --format yaml --file my_entries/ ``` The contents of `my_entries/` will then look like this: ``` output my_entries/ |- 2013_06_03_a-beautiful-day.yaml |- 2013_06_07_dinner-with-gabriel.yaml |- ... ``` --- ### Installation # Getting started ## Installation The easiest way to install `jrnl` is using [pipx](https://pipx.pypa.io/stable/installation/) with [Python](https://www.python.org/) 3.11+: ``` sh pipx install jrnl ``` !!! tip Do not use `sudo` while installing `jrnl`. This may lead to path issues. The first time you run `jrnl` you will be asked where your journal file should be created and whether you wish to encrypt it. ## Quickstart To make a new entry, just type ``` text jrnl yesterday: Called in sick. Used the time to clean, and spent 4h on writing my book. ``` and hit return. `yesterday:` will be interpreted as a time stamp. Everything until the first sentence mark (`.?!:`) will be interpreted as the title, the rest as the body. In your journal file, the result will look like this: ``` output 2012-03-29 09:00 Called in sick. Used the time to clean the house and spent 4h on writing my book. ``` If you just call `jrnl`, you will be prompted to compose your entry - but you can also [configure](advanced.md) *jrnl* to use your external editor. --- ### Journal Types # Journal Types `jrnl` can store your journal in a few different ways: - a single text file (encrypted or otherwise) - a folder structure organized by date containing unencrypted text files - the DayOne Classic format There is no need to specify what type of journal you'd like to use. Instead, `jrnl` will automatically detect the journal type based on whether you're referencing a file or a folder in your [config file](advanced.md), and if it's a folder, whether or not DayOne Classic content exists in it. ## Single File The single file format is the most flexible, as it can be [encrypted](encryption.md). To use it, enter any path that is a file or does not already exist. You can use any extension. `jrnl` will automatically create the file when you save your first entry. ## Folder The folder journal format organizes your entries into subfolders for the year and month and `.txt` files for each day. If there are multiple entries in a day, they all appear in the same `.txt` file. The directory tree structure is in this format: `YYYY/MM/DD.txt`. For instance, if you have an entry on May 5th, 2021 in a folder journal at `~/folderjournal`, it will be located in: `~/folderjournal/2021/05/05.txt` !!! note Creating a new folder journal can be done in two ways: * Create a folder with the name of the journal before running `jrnl`. Otherwise, when you run `jrnl` for the first time, it will assume that you are creating a single file journal instead, and it will create a file at that path. * Create a new journal in your [config_file](advanced.md) and end the path with a ``/`` (on a POSIX system like Linux or MacOSX) or a ``\`` (on a Windows system). The folder will be created automatically if it doesn't exist. !!! note Folder journals can't be encrypted. ## Day One Classic `jrnl` supports the original data format used by DayOne. It's similar to the folder journal format, except it's identified by either of these characteristics: * the folder has a `.dayone` extension * the folder has a subfolder named `entries` This is not to be confused with the DayOne 2.0 format, [which is very different](https://help.dayoneapp.com/en/articles/1187337-day-one-classic-is-retired). !!! note DayOne Classic journals can't be encrypted. ## Changing your journal type You can't simply modify a journal's configuration to change its type. Instead, define a new journal as the type you'd like, and use [piping](https://en.wikipedia.org/wiki/Redirection_(computing)#Piping) to export your old journal as `txt` to an import command on your new journal. For instance, if you have a `projects` journal you would like to import into a `new` journal, you would run the following after setting up the configuration for your `new` journal: ``` jrnl projects --format txt | jrnl new --import ``` --- ### Privacy And Security # Privacy and Security `jrnl` is designed with privacy and security in mind, but like any other program there are some limitations to be aware of. ## Password strength `jrnl` doesn't enforce password strength requirements. Short or commonly-used passwords can be easily circumvented by someone with basic security skills to access to your encrypted `jrnl` file. ## Plausible deniability You may be able to hide the contents of your journal behind a layer of encryption, but if someone has access to your configuration file, then they can figure out that you have a journal, where that journal file is, and when you last edited it. With a sufficient power imbalance, someone may be able to force you to unencrypt it through non-technical means. ## Spying While `jrnl` can protect against unauthorized access to your journal entries while it isn't open, it cannot protect you against an unsafe computer/location. For example: - Someone installs a keylogger, tracking what you type into your journal. - Someone watches your screen while you write your entry. - Someone installs a backdoor into `jrnl` or poisons your journal into revealing your entries. ## Saved Passwords When creating an encrypted journal, you'll be prompted as to whether or not you want to "store the password in your keychain." This keychain is accessed using the [Python keyring library](https://pypi.org/project/keyring/), which has different behavior depending on your operating system. In Windows, the keychain is the Windows Credential Manager (WCM), which can't be locked and can be accessed by any other application running under your username. If this is a concern for you, you may not want to store your password. ## Shell history Since you can enter entries from the command line, any tool that logs command line actions is a potential security risk. See below for how to deal with this problem in various shells. ### bash You can disable history logging for jrnl by adding this line into your `~/.bashrc` file: ``` sh HISTIGNORE="$HISTIGNORE:jrnl *" ``` To delete existing `jrnl` commands from `bash` history, simply delete them from your bash history file. The default location of this file is `~/.bash_history`, but you can run `echo "$HISTFILE"` to find it if needed. Also, you can run `history -c` to delete all commands from your history. ### zsh You can disable history logging for jrnl by adding this to your `~/.zshrc` file: ``` sh setopt HIST_IGNORE_SPACE alias jrnl=" jrnl" ``` To delete existing `jrnl` commands from `zsh` history, simply remove them from your zsh history file. The default location of this file is `~/.zsh_history`, but you can run `echo "$HISTFILE"` to find it if needed. Also, you can run `history -c` to delete all commands from your history. ### fish By default `fish` will not log any command that starts with a space. If you want to always run jrnl with a space before it, then you can add this to your `~/.config/fish/config.fish` file: ``` sh abbr --add jrnl " jrnl" ``` To delete existing jrnl commands from `fish` history, run `history delete --prefix 'jrnl '`. ### Windows Command Prompt Windows doesn't log history to disk, but it does keep it in your command prompt session. Close the command prompt or press `Alt`+`F7` to clear your history after journaling. ## Files in transit from editor to jrnl When creating or editing an entry, `jrnl` uses a unencrypted temporary file on disk in order to give your editor access to your journal. After you close your editor, `jrnl` then deletes this temporary file. So, if you have saved a journal entry but haven't closed your editor yet, the unencrypted temporary remains on your disk. If your computer were to shut off during this time, or the `jrnl` process were killed unexpectedly, then the unencrypted temporary file will remain on your disk. You can mitigate this issue by only saving with your editor right before closing it. You can also manually delete these files from your temporary folder. By default, they are named `jrnl*.jrnl`, but if you use a [template](reference-config-file.md#template), they will have the same extension as the template. ## Editor history Some editors keep usage history stored on disk for future use. This can be a security risk in the sense that sensitive information can leak via recent search patterns or editor commands. ### Visual Studio Code Visual Studio Code stores the contents of saved files to allow you to restore or review the contents later. You can disable this feature for all files by unchecking the `workbench.localHistory.enabled` setting in the [Settings editor](https://code.visualstudio.com/docs/getstarted/settings#_settings-editor). Alternatively, you can disable this feature for specific files by configuring a [pattern](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options) in the `workbench.localHistory.exclude` setting. To exclude unencrypted temporary files generated by `jrnl`, you can set the `**/jrnl*.jrnl` (unless you are using a [template](reference-config-file.md#template)) pattern for the `workbench.localHistory.exclude` setting in the [Settings editor](https://code.visualstudio.com/docs/getstarted/settings#_settings-editor). !!! note On Windows, the history location is typically found at `%APPDATA%\Code\User\History`. Visual Studio Code also creates a copy of all unsaved files that are open. It stores these copies in a backup location that's automatically cleaned when you save the file. However, if your computer shuts off before you save the file, or the Visual Studio Code process stops unexpectedly, then an unencrypted temporary file may remain on your disk. You can manually delete these files from the backup location. !!! note On Windows, the backup location is typically found at `%APPDATA%\Code\Backups`. ### Vim Vim stores progress data in a so called Viminfo file located at `~/.viminfo` which contains all sorts of user data including command line history, search string history, search/substitute patterns, contents of register etc. Also to be able to recover opened files after an unexpected application close Vim uses swap files. These options as well as other leaky features can be disabled by setting the `editor` key in the Jrnl settings like this: ``` yaml editor: "vim -c 'set viminfo= noswapfile noundofile nobackup nowritebackup noshelltemp history=0 nomodeline secure'" ``` To disable all plugins and custom configurations and start Vim with the default configuration `-u NONE` can be passed on the command line as well. This will ensure that any rogue plugins or other difficult to catch information leaks are eliminated. The downside to this is that the editor experience will decrease quite a bit. To instead let Vim automatically detect when a Jrnl file is being edited an autocommand can be used. Place this in your `~/.vimrc`: ``` vim autocmd BufNewFile,BufReadPre *.jrnl setlocal viminfo= noswapfile noundofile nobackup nowritebackup noshelltemp history=0 nomodeline secure ``` !!! note If you're using a [template](reference-config-file.md#template), you will have to use the template's file extension instead of `.jrnl`. See `:h