Cor - Plain text knowledge management for the terminal
Project description
Track projects, tasks, ideas, and progress using markdown files and git.
Philosophy
- Plain text + git + minimal tooling - Simple, using open formats.
- Writing is thinking - Tools assist, not replace. The editor is the main interface. The writing and thinking should be the main driver to organize the content.
- Files over folders - Flat structure with dot notation (
project.group.task.md).archivefolder serve to hide unactive files.
Installation
pip install cor-text
Or install from source:
pip install -e .
Dependencies
- ripgrep (rg) - Required for content search (
cor search)# Ubuntu/Debian sudo apt-get install ripgrep # Arch Linux sudo pacman -S ripgrep # Via conda conda install -c conda-forge ripgrep
Development
pip install -e ".[dev]" # Install with test dependencies
pytest # Run all tests
pytest tests/test_cli.py # Run CLI tests only
pytest tests/test_precommit.py # Run pre-commit hook tests
pytest -v # Verbose output
Test Coverage
The test suite covers:
- CLI commands:
init,new,edit,mark,sync,projects,tree, (rename|move) - Pre-commit hook: Status sync, archiving, unarchiving, task groups, separators
- Edge cases: Multi-task commits, group status propagation, link updates
Quick Start
# 1. Create a directory for your vault
mkdir ~/notes
cd ~/notes
# 2. Initialize Cortex vault
# This creates the vault structure, initializes git, and installs git hooks
cor init
# Or create an example vault to explore features
cor example-vault
# Create a new project
cor new project my-project
# Create a task under a project (use dot notation + tab completion)
cor new task my-project.implement-feature
# Create a standalone note
cor new note meeting-notes
# Check what needs attention
cor daily
# Summarize recent work
cor weekly
# Git sync
cor sync
File Types
| Pattern | Type | Purpose |
|---|---|---|
project.md |
Project | Main project file with goals, scope, done criteria |
project.task.md |
Task | Actionable item within a project |
project.group.md |
Task Group | Organizes related tasks (also a task itself) |
project.group.task.md |
Task | Nested task under a task group |
project.group.smaller_group.task.md |
Task | Deeply nested task (supports any depth) |
project.note.md |
Note | Reference/thinking, not actionable |
backlog.md |
Backlog | Unsorted inbox for capture |
root.md |
Root | Dashboard/digest of current state |
Metadata Reference
All files use YAML frontmatter. See schema.yaml for full specification.
Common Fields
| Field | Type | Description |
|---|---|---|
created |
date | Auto-set by cor new |
modified |
date | Auto-updated by git hook |
due |
date | Deadline (optional) |
priority |
enum | low | medium | high |
tags |
list | Freeform tags |
Project Status
| Value | Description |
|---|---|
planning |
Defining goals/scope |
active |
Currently being worked on |
paused |
Temporarily on hold |
done |
Done, goals achieved |
Task Status
| Value | Symbol | Description |
|---|---|---|
todo |
[ ] |
Ready to start |
active |
[.] |
Currently in progress |
blocked |
[o] |
Blocked, cannot proceed |
waiting |
[/] |
Waiting on external input (other people/AIs) |
done |
[x] |
Completed (archived) |
dropped |
[~] |
Cancelled/abandoned |
Example
---
created: 2025-12-30
modified: 2025-12-30
status: active
due: 2025-01-15
priority: high
tags: [coding, urgent]
---
Commands
| Command | Description |
|---|---|
cor init |
Initialize vault (creates structure, initializes git, installs hooks) |
cor new <type> <name> |
Create file from template (project, task, note) |
cor expand <task> |
Expand task checklist into individual subtasks |
cor edit <name> |
Open existing file in editor (use -a to include archived) |
cor mark <name> <status> |
Change task status (todo, active, blocked, done, dropped) |
cor sync |
Pull, commit all changes, and push to remote (--no-pull, --autostash) |
cor daily [tag] |
Show today's tasks; when tag is provided, only tasks matching the tag (by project name, task tags, or project tags) |
cor weekly |
Show this week's summary |
cor projects |
List active projects with status and last activity (from children) |
cor tree <project> |
Show task tree for a project with status symbols |
cor review |
Interactive review of stale/blocked items |
cor rename <old> <new> |
Rename project/task with all dependencies |
cor move <old> <new> |
Alias of rename (conceptually better for moving groups/tasks) |
cor group <project.group> <tasks> |
Group existing tasks under a new task group |
cor process |
Process backlog items into projects |
cor hooks install |
Install pre-commit hook and shell completion |
cor hooks uninstall |
Remove git hooks |
cor config vault <path> |
Set global vault path |
cor config inbox <token> |
Configure Telegram bot for mobile inbox |
cor config |
Show current configuration |
cor inbox |
Test Telegram connection and show pending messages |
cor calendar auth |
Authenticate with Google Calendar |
cor calendar sync |
Sync due dates to Google Calendar |
cor calendar status |
Check calendar authentication status |
cor calendar logout |
Remove Google Calendar credentials |
cor maintenance sync |
Manually run archive/status sync |
cor search <query> |
Full-text content search (supports filters: status:, #tag, project:) |
Bulk Operations
Perform operations on multiple files at once using glob patterns:
# Bulk status update
cor mark "project.*" done # Mark all project tasks as done
cor mark "project.group.*" active # Mark group tasks as active
cor mark -s done "project.*" # Alternative syntax with --status flag
# Bulk move/rename
cor move "project.old-*" "project.new-*" # Rename matching tasks
cor move "p1.*" "p2.*" # Move all tasks to different project
cor move "*.old.*" "*.new.*" --dry-run # Preview changes without applying
Pattern wildcards:
*matches any sequence of characters?matches a single character[abc]matches any character in brackets
Confirmation: Operations affecting more than 3 files require confirmation. Use --dry-run to preview changes first.
Search
Full-text content search using ripgrep (fast, no indexing required):
# Basic content search
cor search "neural network"
# Search with filters
cor search "status:active ML"
cor search "#urgent"
cor search "project:foundation_model"
# Include archived files
cor search "experiments" -a
# Limit results
cor search "training" -n 50
# Compact output (no context lines)
cor search "TODO" --no-context
Sync & Conflict Resolution
When working across multiple machines, sync conflicts can occur:
# Normal sync (pull → commit → push)
cor sync
# Skip pull (commit local changes only)
cor sync --no-pull
# Auto-stash local changes, pull, then restore
cor sync --autostash
# Commit only, don't push
cor sync --no-push
Natural Language Dates and Tags
The cor new task command supports natural language date and tag parsing:
Due Dates: Use due <date> to set a due date with natural language
cor new task project.taskname description due tomorrow
cor new task project.taskname description due next friday
cor new task project.taskname description due 2026-02-15
Tags: Use tag <tag1> <tag2> to add tags
cor new task project.taskname description tag urgent
cor new task project.taskname description tag ml nlp research
Combined: Use both in the same command
cor new task project.taskname finish the pipeline due tomorrow tag urgent ml
cor new task project.taskname code review due next friday tag review quality
Supported date formats include: tomorrow, today, next friday, in 3 days, 2026-02-15, and many more natural language expressions.
References (Bibliography)
Manage bibliography as markdown notes in ref/ and a BibLaTeX file ref/references.bib.
-
Add: Add a reference from a DOI or URL.
- Command:
cor ref add <identifier> [--key KEY] [--tags TAG ...] [--no-edit] - Identifier can be:
- A DOI:
10.xxxx/abcd.2024 - A DOI URL:
https://doi.org/10.xxxx/abcd.2024or publisher paths containing a DOI (e.g.,https://www.biorxiv.org/content/10.1101/...) - An arXiv URL or ID:
https://arxiv.org/abs/1706.03762or1706.03762(mapped to10.48550/arXiv.<id>)
- A DOI:
- Behavior: creates
ref/<citekey>.mdand updatesref/references.bib. - Note: does not scrape publisher pages. If the URL does not contain a DOI, a friendly error explains how to supply one.
- Command:
-
List: Show all references.
- Command:
cor ref list [--format table|short]
- Command:
-
Show: Display details for a reference.
- Command:
cor ref show <citekey>
- Command:
-
Edit: Open the reference note.
- Command:
cor ref edit <citekey>
- Command:
-
Delete: Remove the reference note.
- Command:
cor ref del <citekey> [--force]
- Command:
-
Search (experimental): Text search across stored reference metadata.
- Command:
cor ref search <query> [--limit N]
- Command:
Examples:
# Add from DOI
cor ref add 10.1101/2025.07.24.666581
# Add from DOI URL
cor ref add https://doi.org/10.1101/2025.07.24.666581
# Add from publisher URL (DOI embedded in path)
cor ref add https://www.biorxiv.org/content/10.1101/2025.07.24.666581v1
# Add from arXiv ID
cor ref add 1706.03762
# Custom citekey and tags
cor ref add 10.1101/2025.07.24.666581 --key smith2026transformers --tags ml --tags nlp
Configuration
Vault Path Setup
Cor automatically configures your vault path in ~/.config/cor/config.yaml when you run cor init. You can change it anytime:
# Set during initial setup
cor init
# Or reconfigure later
cor config vault /path/to/notes
Once configured, you can run cor commands from any directory:
# Commands work from anywhere after init
cd /tmp
cor daily
cor new task my-project.quick-idea
Config File Format
~/.config/cor/config.yaml:
vault: /home/user/notes # Vault path (required)
verbosity: 1 # 0=silent, 1=normal, 2=verbose, 3=debug
remote_inbox: 123456:ABC... # Telegram bot token (optional)
### Configuration Commands
```bash
cor config # Display current config
cor config vault <path> # Set vault path
cor config verbosity <0-3> # Set verbosity level
cor config inbox <token> # Configure Telegram inbox
Mobile Inbox via Telegram
Capture notes from your phone by sending messages to a Telegram bot. Messages are automatically pulled into your backlog during cor sync.
Setup (2 minutes)
-
Create a Telegram bot:
- Open Telegram and message @BotFather
- Send
/newbotand follow the prompts to create your bot - Copy the bot token (looks like
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)
-
Configure Cortex:
cor config inbox <your-bot-token>
-
Initialize the bot:
- Find your bot in Telegram (search for the username you created)
- Send
/startto your bot - Send a test message
-
Test the connection:
cor inbox # Shows pending messages
-
Sync to pull messages:
cor sync # Pulls messages into backlog and clears them from Telegram
Google Calendar Integration
Sync task due dates to Google Calendar. Events are created automatically when you run cor sync (if authenticated).
-
Authenticate:
cor calendar auth
- This opens a browser for Google sign-in
- Grant permission to manage your calendar
- The refresh token is stored securely (you won't need to do this again)
-
Verify:
cor calendar status # Should show "✓ Authenticated"
Usage
# Sync due dates manually
cor calendar sync
# Sync to a different calendar
cor calendar sync -c "My Work Calendar"
# Check authentication status
cor calendar status
# Logout and remove stored credentials
cor calendar logout
Auto-sync: When you run cor sync, calendar events are updated automatically if you're authenticated.
How it works:
- Creates events for tasks with
due:dates that are not done/dropped - Updates existing events when due dates change
- Creates a "Cor Tasks" calendar if it doesn't exist
- Events include task status in the title:
[active] Task name
File Hierarchy & Linking
Cor uses dot notation for hierarchy: project.group.task.md
Forward links (parent → children):
## Tasks
- [ ] [Implement API](project.implement-api)
- [.] [Testing group](project.testing)
Backlinks (child → parent):
[< Project Name](project)
Links use relative paths to maintain compatibility when files are archived:
- Active child → Active parent:
[< Parent](parent) - Archived child → Active parent:
[< Parent](../parent) - Active child → Archived parent: Not typical, but supported
Renaming & Moving Files
Use cor rename or cor move to safely refactor your vault. The hook automatically:
- Updates all forward links in parents
- Updates all backlinks in children
- Updates
parentfield in child frontmatter - Updates all descendants' parent chains
- Moves files to/from archive as needed
# Rename a project (updates all tasks)
cor rename old-project new-project
# Rename a task
cor rename project.old-task project.new-task
# Move a group to a different project
cor move p1.experiments p2.experiments
# Preview changes before committing
cor rename old-project new-project --dry-run
# Commit the changes
git add -A && git commit -m "Rename project"
Converting Tasks to Groups
When designing complex features, you might start with a single task and then realize it needs to be broken down. Cortex makes this easy by expanding checklist items into individual subtasks:
Before - Single task with checklist (my-project.feature.md):
## Description
Implement new authentication feature:
- [ ] design-api
- [ ] implement-backend
- [ ] write-tests
- [ ] update-documentation
After running cor expand my-project.feature:
- Creates
my-project.feature.design-api.md - Creates
my-project.feature.implement-backend.md - Creates
my-project.feature.write-tests.md - Creates
my-project.feature.update-documentation.md - Updates
my-project.feature.mdwith proper task links - Removes the original checklist
The task becomes a proper task group with full hierarchy and linking support.
Completion Configuration
Control fuzzy completion behavior via environment variable:
# Allow cycling through all 100%-score matches (default, recommended)
export COR_COMPLETE_COLLAPSE_100=0
# Collapse to shortest match only (faster single-result completion)
export COR_COMPLETE_COLLAPSE_100=1
Shell Setup
Shell completion is automatically configured when you run cor init. The setup detects your shell (zsh or bash) and adds the necessary completion code to your shell config file.
Zsh
After running cor init, optionally add to your ~/.zshrc to enable Tab cycling through suggestions:
Then reload:
source ~/.zshrc # or .bashrc
Directory Structure
User Configuration & Vault
~/.config/cortex/
├── config.yaml # Global config (vault path, verbosity)
└── google_credentials.pickle # Google Calendar auth (chmod 600)
~/.zshrc or ~/.bashrc # Shell completion automatically added here
your-vault/ # Your notes directory
├── .git/ # Git repository (auto-initialized by cor init)
│ └── hooks/
│ └── pre-commit # Auto-maintenance hook
├── root.md # Dashboard/digest of current state
├── backlog.md # Unsorted inbox for capture
├── archive/ # Completed/archived items
│ ├── old-project.md
│ ├── project.old-task.md
│ └── ...
└── templates/ # File templates
├── project.md
├── task.md
└── note.md
Project Source (Development)
cor/ # Repository root
├── cor/ # Main package
│ ├── __init__.py
│ ├── cli.py # Command-line interface
│ ├── config.py # Vault path resolution
│ ├── parser.py # YAML/markdown parsing
│ ├── schema.py # Data schema & validation
│ ├── utils.py # Utility functions
│ ├── completions.py # Shell completion logic
│ ├── fuzzy.py # Fuzzy matching for search
│ ├── maintenance.py # Auto-sync & archiving
│ ├── commands/ # Command implementations
│ │ ├── __init__.py
│ │ ├── process.py # Backlog processing
│ │ ├── refactor.py # Rename/move operations
│ │ └── status.py # Status display
│ ├── hooks/ # Git integration
│ │ └── pre-commit # Pre-commit hook script
│ └── assets/ # Built-in templates & schema
│ ├── schema.yaml
│ ├── project.md
│ ├── task.md
│ ├── note.md
│ ├── backlog.md
│ └── root.md
├── tests/ # Test suite
│ ├── conftest.py # Test configuration
│ ├── test_cli.py # CLI command tests
│ ├── test_delete.py # Delete operation tests
│ ├── test_maintenance.py # Hook & sync tests
│ ├── test_precommit.py # Pre-commit hook tests
│ ├── test_rename_*.py # Rename/move tests
│ └── __pycache__/
├── pyproject.toml # Project config & dependencies
├── README.md # This file
├── LICENSE # MIT License
└── MANIFEST.in # Package manifest
Git Hooks & Automation
The pre-commit hook automatically runs on every commit to keep your vault consistent. It is automatically installed when you run cor init.
What the Hook Does
Validation & Consistency:
- Validates frontmatter - Checks status/priority values against schema
- Detects broken links - Blocks commits with missing link targets
- Prevents orphan files - Files must have valid parent references
- Detects partial renames - Ensures all related files are renamed together
Automatic Updates:
5. Updates modified dates - Sets modified field to current timestamp (YYYY-MM-DD HH:MM)
6. Handles file renames - When you rename a file:
- Updates all parent links (adds/removes task entries)
- Updates all child parent references
- Updates backlinks with new parent title
- Preserves link semantics (relative paths for archive)
- Archives completed items - Moves to
archive/whenstatus: done - Unarchives reactivated items - Moves back from archive when status changes from done
- Syncs task status - Updates parent checkboxes to match task status:
[ ]= todo,[.]= active,[o]= blocked,[/]= waiting,[x]= done,[~]= dropped
Hierarchy & Organization:
10. Updates task group status - Calculates from children (blocked > active > done > todo)
11. Updates project status - Sets to active if any task is active, back to planning when none
12. Sorts tasks - By status (blocked, active, waiting, todo, then done, dropped)
13. Adds separators - Inserts --- between active and completed tasks for readability
How It Works
The hook uses git diff --cached to detect changes, so it only processes modified files:
git add my-project.task.md # Stage changes
git commit -m "Update task" # Hook runs automatically
Disabling Temporarily
git commit --no-verify -m "Skip hook" # Bypass hook for this commit
Manual Sync
To manually run the sync logic on all files (useful after bulk edits):
cor maintenance sync # Preview changes
cor maintenance sync --all # Sync all files (not just modified)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cortext_cli-0.1.0.tar.gz.
File metadata
- Download URL: cortext_cli-0.1.0.tar.gz
- Upload date:
- Size: 175.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2266b1f63d3f565b2a1d9d35f8b8349ce3e9d2b19ab04ef1d4e946801816e3aa
|
|
| MD5 |
f29604ae8fca9f4b2e4a51aa90a28e35
|
|
| BLAKE2b-256 |
eeb488cf90cba3b9b4538e69bb74f48737b6d12045272780ae339a220aaa7483
|
File details
Details for the file cortext_cli-0.1.0-py3-none-any.whl.
File metadata
- Download URL: cortext_cli-0.1.0-py3-none-any.whl
- Upload date:
- Size: 153.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b47ed9132286513b6e0deb5baa52ce8b17f662759d461c6e9ce3d29ac3584cb3
|
|
| MD5 |
bc54b009207c2585ceaf845f95aa2a44
|
|
| BLAKE2b-256 |
3a38ee5651e2abe757b6cc7b028100e5ab0c044232a97b771ecf01a41ddaac3d
|