{"id":26503089,"url":"https://github.com/quantiusbenignus/speedo","last_synced_at":"2026-04-05T20:37:45.684Z","repository":{"id":219372011,"uuid":"604799288","full_name":"QuantiusBenignus/speedo","owner":"QuantiusBenignus","description":"Speak right into your todo.txt with speedo. Set tags, priority, due dates directly from speech.","archived":false,"fork":false,"pushed_at":"2023-03-29T14:34:03.000Z","size":141,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-03T20:54:58.914Z","etag":null,"topics":["cli","command-line","date","date-parser","linux","natural-language","reminders","shell","speech-recognition","speech-to-text","todo","todoapp","todolist","todotxt","todotxt-cli","txt-based","whisper","zsh"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/QuantiusBenignus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-02-21T20:16:33.000Z","updated_at":"2024-07-12T23:53:40.000Z","dependencies_parsed_at":"2024-01-27T01:58:17.533Z","dependency_job_id":"a9677af5-491c-4b9d-b3f2-23e395af878f","html_url":"https://github.com/QuantiusBenignus/speedo","commit_stats":null,"previous_names":["quantiusbenignus/speedo"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/QuantiusBenignus/speedo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QuantiusBenignus%2Fspeedo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QuantiusBenignus%2Fspeedo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QuantiusBenignus%2Fspeedo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QuantiusBenignus%2Fspeedo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/QuantiusBenignus","download_url":"https://codeload.github.com/QuantiusBenignus/speedo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QuantiusBenignus%2Fspeedo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31449830,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T15:22:31.103Z","status":"ssl_error","status_checked_at":"2026-04-05T15:22:00.205Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","command-line","date","date-parser","linux","natural-language","reminders","shell","speech-recognition","speech-to-text","todo","todoapp","todolist","todotxt","todotxt-cli","txt-based","whisper","zsh"],"created_at":"2025-03-20T18:58:05.721Z","updated_at":"2026-04-05T20:37:45.665Z","avatar_url":"https://github.com/QuantiusBenignus.png","language":"Shell","readme":"# Speak right into your todo.txt with `speedo`\n---\n## Record yout todo.txt tasks, set due dates, priority and tags directly from speech.\n![speedo.png](speedo.png)\n\nThis zsh command line utility for Linux records a voice memo from the microphone or uses audio file(s) as the input and then transcribes OFFLINE each input (using whisper.cpp, a C/C++ port of OpenAI's Whisper engine) into text, formated as to-do task in todo.txt or Confluence style (among others). \n\nThe due date, context and priority fields in the todo.txt task can optionally be set with command line flags: \n```\nspeedo\nspeedo -c\nspeedo -w ME -p A\n```\nor extracted from the transcribed text, using user-configurable keywords. The format of the spoken task body could be something like:\n```\n\"\u003cFREE-FORM SPEECH\u003e [$datekey \u003cTIME REFERENCE\u003e] [$hashkey|$priorkey \u003cTAGS|PWORD\u003e] \n```\nFor example, invoking `speedo -w ME`  and speaking:\n\n\u003e\"I have to see my dentist next week. ***Reminder*** for Tuesday. ***hashtag*** health.\" or\n\n\u003e \"Return customer call ASAP. ***Reminder*** tonight at 8. ***Priority*** Alpha. ***Hashtag*** work. \"\n\nwill result in the following lines in todo.txt (or its equivalent):\n```\n.\n.\n() 2023-02-21  I have to see my dentist next week. Reminder for Tuesday. +health @ME due:2023-02-22\n(A) 2023-02-21  Return customer call ASAP, reminder tonight at 8. +work @ME due:2023-02-21T20:00\n\n```\n\nFor more info, invoking  `speedo  --help` will output:\n\n```\n             .~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.\n             |  speedo - Create a todotxt task and set tags, context, priority   |\n             |    via speech. The Linux CLI power at the tip of your tongue!     |\n             *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*\n    Records a voice memo from the microphone or uses audio file(s) as the input. \n    Transcribes each input (using whisper.cpp, a C/C++ port of OpenAI's Whisper engine) into text,\n    formated as to-do task in a todo.txt (or Confluence) style among others. \n      \n    SYNOPSIS: speedo [-b|-c|-s|-bc|-cb|-h|-d datetimespec|-w assignee|-p plevel] ... [filename(s)]\n      - 'speedo' use the default \"tiny\" whisper.cpp ASR model file and create a to-do note  \n      - 'speedo -h|--help' will print this text\n      - 'speedo -b|--base' transcribes a to-do using the larger (more accurate but slower) \"base\" model\n      - 'speedo -c|--clip' transcribe and send the text to the clipboard, formated as inline to-do \n      - 'speedo -s|--style' switches from todo.txt format (default) to the one used in Confluence to dos.  \n      - 'speedo -d|--due datetimespec' create a to-do task with due date set by \"datetimespec\"\n      - 'speedo -p|--priority PWORD' assign a single word priority to this task, 5 levels suggested.\n      - 'speedo -w|--who assignee' add @assignee (or @context for todo.txt format) field to the inline to-do.\n      - 'speedo -[cb]a datetimespec' valid compound options OK, e.g. //datetimespec field in inline to-dos. \n      - any and all non-option arguments are treated as input audio files to be converted\n\n    If explicit datetime not supplied, transcribed text is parsed for a valid datetime for the due date.  \n    It is quite difficult for computers to parse our spoken time references and using only built-in tools\n    (i.e. date -d from coreutils) presents a huge challenge when parsing arbitrary datetime text. \n    A keyword set to the last \"reminder\" in the transcribed text is used to isolate the time reference:\n    \n    Spoken format: \"\u003cFREE FORM SPEECH\u003e [reminder \u003cTIME REFERENCE\u003e] [hashtag|priority \u003cTAGS|PWORD\u003e] \n    \n    EXAMPLES:\n      \"Need to see my dentist next week. Set reminder for Tuesday. hashtag health.\"       - this is valid.\n      \"Scheduled a company meeting with reminder for 2023-5-24 at 8 am. priority high. hashtag work.\" - OK.\n      \"Withdraw old reminder and set new reminder for March the 3rd in the evening, priority top.\"  -OK.\n             ( \"... reminder for next week\"\n      Also   | \"... reminder in 3 hours, priority alpha\"\n      valid: { \"... reminder tomorrow morning\"  (see source code for \"morning\" \u0026 other adjustable definitions)\n             | \"... reminder in 33 hours and 5 minutes\"\n             ( \"... reminder on Thanksgiving day in 15 years, hashtag family\"\n      Custom:  \"... reminder at the usual time. hashtag fun.\" allows customization (see code for ideas)\n    Speaking literaly \"YYYY-MM-DD\", followed by time (if needed) e.g. \"2024 dash 5 dash 23 at 1pm\" works well.\n    In some edge cases, successful parsing gives incorrect datetime. Some practice needed to avoid those.\n    For scheduling critically-important stuff with this utility, use the command-line option \"-d\" \n    and provide explicit datetimespec or instead, simply set the to-do date in the text file.\n\n    NOTE:   Only the text BEFORE the 1st \"hashtag\" (or \"priority\") in the transcribed text will be displayed,\n    including the time reference. The rest is cut and parsed for tags and/or priority and MUST be of the form:\n    \"...hashtag TAG1,...priority PWORD,...hashtag TAGn\", in no particular order with only [,.?] allowed.  \n\n```\n\t\n#### PREPARING THE ENVIRONMENT\n\n##### PREREQUISITES:\n- zsh command line shell installation   \n- whisper.cpp installation (see https://github.com/ggerganov/whisper.cpp) \n- recent versions of 'sox', 'xsel'  command-line tools from your system's repositories.\n-  A working microphone (in GNOME one can set a keyboard shortcut to turn it ON and OFF )  \n\u003e *DISCLAIMER: Setting up the environment for this to work requires a bit of attention and, quite likely for the novice user, reading about the Linux internals and making informed choices. Some of the proposed actions, if implemented, will alter how your system works internally (e.g. systemwide temporary file storage and memory management). The author neither takes credit nor assumes any responsibility for any outcome that may or may not result from interacting with the contents of this document.*\n\n##### Temporary directory and files\n*(NB. Everything in this section is based on the author's choice and opinion and may not fit the taste or the particular situation of everyone; please, adjust the script as you like. )*\n\nAudio-to-text transcription is memory- and CPU-intensive task and fast storage for read and write access can only help. That is why **vm** and **td** are designed to store temporary and resource files in memory, for speed and to reduce SSD/HDD \"grinding\": `TEMPD='/dev/shm'`. \nThis mount point of type \"tmpfs\" is created in RAM (let's assume that you have enough, say, at least 8GB) and is made available by the kernel for user-space applications. When the computer is shut down it is automatically wiped out, which is fine since we do not need the intermediate files.\nIn fact, for Joplin and any other applications (Electron-based or not) that are stored in Appimage format, it would be beneficial (IMHO) to have the systemwide /tmp mount point also kept in RAM. Every time you start Joplin, it expands itself in /tmp writing about 500 MB to your SSD or HDD and moving /tmp to RAM may speed up application startup a bit. A welcome speedup for any Electron app.  In its simplest form, this transition is easy, just run:\n```bash\necho \"tmpfs /tmp tmpfs rw,nosuid,nodev\" | sudo tee -a /etc/fstab\n```\nand then restart your Linux computer.\nFor the aforementioned reasons, the scripts also expect to find the ASR model files needed by whisper.cpp in the same location (/dev/shm). These are large files, that can be transferred to this location at the start of a terminal session (or at system startup). This can be done using your .zshrc (or .bashrc) file by placing something like this in it: \n```bash\n([ -f /dev/shm/ggml-tiny.en.bin ] || cp /path/to/your/local/whisper.cpp/models/ggml* /dev/shm/)\n```\n\n##### \"INSTALLATION\"\n*(Assuming whisper.cpp is available and the \"main\" executable compiled with 'make' in the cloned whisper.cpp repo. See Prerequisites section)*\n* Place the script **speedo** (or, for bash users, **speedo.bash**) somewhere in your PATH. \n* Create a symbolic link (the code expects 'transcribe' in your PATH) to the compiled \"main\" executable in the whisper.cpp directory. For example, create it in your $HOME/bin\u003e with \n```bash\nln -s /full/path/to/whisper.cpp/main $HOME/bin/transcribe\n```  \nIf you are using the GNOME integration (recommended), don't forget to:\n* Place `speedo.desktop` in `$HOME/.local/share/applications/\n* Replace USERNAME and YOURPROFILENAME in the file with your values.\n* Move the icon referenced in the .desktop file to the specified directory in $HOME/.local/...\n* Find \"Speedo\" in your Activities and click \"Add to Favorites\" to pin it to the dock\n* Create a new profile in gnome-terminal and edit it to suit your taste. Use its name in the .desktop file\n\n##### CONFIGURATION\nInside the script, near the begining, there is a clearly marked section, named **\"USER CONFIGURATION BLOCK\"**, where all the user-configurable variables (described in the following section) have been collected. Most can be left as.\n\n#### Notes\nSox is recording in wav format at 16k rate, the only currently accepted by whisper.cpp:\n`rec -t wav $ramf rate 16k silence 1 0.1 3% 1 3.0 4% `\nIt will attempt to stop on silence of 3s with threshold of 6%, but you can always press CTRL-C to stop it manually. This is the only intervention that may be needed. \nAfter the memo is captured, it will be passed to `transcribe` (whisper.cpp) for speech recognition.\nThis will take a couple of seconds (fewer on a computer with fast CPU). One can adjust the number of processing threads used by adding  `-t n` to the command line parameters of transcribe (please, see whisper.cpp documentation). After transcription, the text is stored in a .txt file (-otxt argument in `transcribe -m $model -f $ramf -otxt`), in this case /dev/shm/vmfile.txt . \nThe script will then parse the text for the relevant special fields, format the data in the appropriate format and send it to either the clipboard (flag -c) or to the todo.txt file. \n\n#### Parsing the transcribed text for a datetime reference (in **speedo** - to set up a due date)\n\n\u003e*(N.B. Only spoken English time constructs, operation in the user's current locale and time zone.)*\n\nIf explicit datetime is not supplied, the transcribed text is parsed for a valid notification/alarm datetime.\nIt is quite difficult for computers to parse our spoken time references and using only built-in tools (i.e. coreutils date -d) presents a huge challenge when parsing arbitrary datetime text.\nThere are dedicated, complex NLP tools that work better but they are not perfect either.\n\nThat is why, to make things a bit easier, a keyword is used to separate the note body from the date-time reference to be parsed. This keyword can be used in the note body freely, it is the last instance within the text that is considered as the separator. For example, if the keyword is **\"notification\"** (this is user-configurable), then the last \"notification\" in the transcribed text is used to isolate the time reference:\nFor example:\n* *\"Need to see my dentist next week. Set **notification** for Tuesday\"*           - this is valid.\n* *\"Scheduled a company meeting with **notification** for 2023/5/24 at 8pm\"*   - also OK.\n* *\"Guests need prior notification. Set one **notification** for March the 3rd in the evening.\"*  -OK\n* *\"...**notification** for next week\"*\n* *\"...**notification** in 3 hours\"*\n* *\"...**notification** tomorrow morning\"*  (see source code for \"morning\" \u0026 other adjustable definitions)\n* *\"...**notification** in 33 hours and 5 minutes\"*\n* *\"...**notification** on the ninth month +1000 seconds\"*\n... are all valid.\n* or even *\"...**notification** at the usual time\"* which allows privacy and customization (see code for ideas).\n\nSpeaking literaly \"YYYY-MM-DD\", followed by time (if needed) e.g. *\"2024 dash 5 dash 23 at 1pm\"* works well too.\nIf parsing is unsuccessful, the utility will not set a due date and it has to be done manualy. A warning will be issued but the to-do task will be created successfully. The failure can be due to errors in the user instructions, errors in the speech recognition, limitations of the simplistic datetime preprocessor etc. With practice (and good diction:-) the error rate can be comparable to the error rate for speech recognition.\nIn some edge cases, successful parsing gives incorrect datetime. Some practice needed to avoid those\nFor scheduling critically-important stuff with this utility, use the command-line option \"-d\"\nand provide explicit *datetime specification* or instead, simply set the due date in the file.\n\n#### Gnome desktop integration\nTo make interaction with this CLI utility more convenient, one can create a GNOME desktop entry (if using GNOME) with a custom profile for the terminal window (small window, custom color, transparent, etc., see `gnome-terminal` documentation on creating named profiles ) so that the terminal window will be unobtrusive. \nOne can also choose whether to keep the terminal window open, or close it after the transcription (see the gnome-terminal settings for your custom profile - YOURPROFILENAME in the code below.)\nSample `speedo.desktop` (Place in your ` $HOME/.local/share/applications/`):\n```\n[Desktop Entry]\nName=Speedo\nComment=For use with the speedo CLI utility\nExec=gnome-terminal --window-with-profile=YOURPROFILENAME --hide-menubar --geometry=64x6+380+920 --title=Speech-to-Todo.txt\nIcon=/home/USERNAME/.local/share/icons/hicolor/128x128/apps/mic128.png\nTerminal=true\nType=Application\nCategories=Application\nActions=new-clip;new-todo;\n\n[Desktop Action new-clip]\nName=To-Do To Clipboard\nExec=gnome-terminal --window-with-profile=YOURPROFILENAME --hide-menubar --geometry=64x6+380+920 --title=NewClip -- speedo -c\n\n[Desktop Action new-todo]\nName=New Joplin ToDo\nExec=gnome-terminal --window-with-profile=YOURPROFILENAME --hide-menubar --geometry=64x6+380+920 --title=NewTodo -- speedo\n\n```\n### Credits\n* Open AI (for [Whisper](https://github.com/openai/whisper))\n* Georgi Gerganov and community ( for Whisper's C/C++ port [whisper.cpp](https://github.com/ggerganov/whisper.cpp))\n* The **sox** developers (for the venerable \"Swiss Army knife of sound processing tools\")\n* The creators and maintainers of old and new utilities such as **xsel, xclip**, the heaviweight **ffmpeg** and others that make the Linux environment (CLI and GUI) such a powerful paradigm.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquantiusbenignus%2Fspeedo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquantiusbenignus%2Fspeedo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquantiusbenignus%2Fspeedo/lists"}