Nira is a local issue tracker for a single workspace.
It gives you:
- a shell-first CLI for automation and tools like Codex
- a local web UI for human editing and browsing
- SQLite storage in
.nira/nira.db - Markdown bodies and resolution notes
- lightweight linking between related tickets
It is intentionally closer to "near Jira" than "mini Jira".
- Python 3.13 or newer
- Jinja2
- SQLAlchemy 2.0+
Nira is a standard Python package. You can install it globally, with pipx, or into a virtual environment.
# Clone the repository
git clone https://github.com/Obscuretone/nira.git
cd nira
# Install using pipx (recommended for CLIs)
pipx install .
# Or install in editable mode for development
python3 -m pip install -e .Alternatively, you can run the ./nira shim script directly from the source directory without installing.
Initialize Nira inside the repo or project directory you want to track:
cd ~/Code/nira
~/Code/nira/nira initBy default, init derives the ticket prefix from the folder name. Single-word folders stay uppercased, and multi-word folder names collapse into an acronym. For example:
~/Code/nirabecomesNIRA~/Code/employment-matching-hubbecomesNIRA~/Code/EmploymentMatchingHubbecomesNIRA
You can override that at init time:
~/Code/nira/nira init --project-key NIRACreate and inspect a ticket:
~/Code/nira/nira new "Evaluate Tortoise alternatives" --source "architecture review"
~/Code/nira/nira list
~/Code/nira/nira show NIRA-1Start the web UI:
~/Code/nira/nira serveThen open http://127.0.0.1:8765.
Ticket labels like NIRA-1 are display keys derived from the current workspace prefix and ticket number. Internally, tickets use integer primary keys in SQLite.
Most commands work from the current directory or any child directory inside a Nira workspace.
Nira walks upward until it finds .nira/.
That means these both work:
cd ~/Code/nira
~/Code/nira/nira listcd ~/Code/nira/app/services
~/Code/nira/nira listIf you want to point at a different workspace explicitly, use --root:
~/Code/nira/nira --root ~/Code/nira listShow built-in help:
./nira help
./nira help newInitialize a workspace:
./nira init
./nira init --project-key NIRACreate tickets:
./nira new "Write release notes"
./nira new "Fix login redirect" --source "user report" --type bug --priority high
./nira new "Draft migration plan" --body "## Summary\nOutline the cutover.\n"
printf '## Summary\nCreated from stdin.\n' | ./nira new "Pipeline-created ticket"List and show tickets:
./nira list
./nira list --status open
./nira list --status in_progress --priority high
./nira list --type bug
./nira show NIRA-1Update tickets:
./nira update NIRA-1 --status in_progress
./nira update NIRA-1 --priority critical --type bug
./nira update NIRA-1 --source "architecture review"Edit long-form content in $EDITOR:
./nira edit NIRA-1
./nira edit NIRA-1 --field resolutionClose and reopen:
./nira close NIRA-1 --reason completed
./nira reopen NIRA-1Link related tickets:
./nira link NIRA-1 NIRA-2
./nira links
./nira links NIRA-1
./nira unlink NIRA-1 NIRA-2Aliases:
createis an alias fornewgetis an alias forshow
Start the server:
./nira serve
./nira serve --host 127.0.0.1 --port 8765
./nira serve --reloadThe web UI is local-only by default.
--reload is intended for local development and restarts the server when Nira source or template files change.
The interface includes:
- a ticket list with filtering by status
- sorting by clicking table headers or using the sort controls
- a create-ticket screen with title, body, source, type, and priority
- a ticket detail page with inline editing
- a settings page for renaming the workspace ticket prefix
- automatic saves when status, priority, or type dropdowns change
- related-ticket linking
- a WYSIWYG Markdown editor for ticket bodies
Changing the workspace prefix updates displayed ticket labels everywhere. For example, renaming the prefix from NIRA to NIRA turns NIRA-4 into NIRA-4 without changing the underlying ticket record.
Current browser-supported ticket types:
taskbug
Current ticket statuses:
openin_progressclosed
In the web UI these are labeled as:
openin progresscompleted
Nira stores all data in:
.nira/nira.db
SQLite is the source of truth. There is no separate export or sync layer.
The database stores:
- workspace settings
- the default ticket prefix
- integer ticket primary keys plus user-facing ticket numbers
- ticket metadata
- Markdown bodies
- Markdown resolution notes
- related ticket links
Set up a local dev environment:
python3 -m venv .venv
source .venv/bin/activate
pip install -e .[dev]Run the full test suite:
pytestThis runs both the focused unit tests in tests/test_unit.py and the end-to-end integration coverage in tests/test_integration.py.
Run static analysis:
ruff check .
mypy --config-file mypy.ini nira_app tests
pyrightConfiguration files:
pyproject.tomlruff.tomlmypy.inipyrightconfig.json
The repo ignores workspace state and local tooling output through .gitignore, including .nira/.
pyproject.toml Package definition and dependencies
nira Optional CLI entrypoint shim
nira_app/cli.py CLI behavior and entrypoint
nira_app/storage.py SQLite storage and ticket operations
nira_app/web.py Local server-rendered web UI and routing
nira_app/templates/ Jinja2 HTML templates for the web interface
nira_app/markdown.py Minimal Markdown renderer for previews
tests/ Integration tests for CLI and HTTP flows
