Skip to main content

tendril

A keyboard-driven JIRA companion. A local SQLite cache mirrors whole JIRA projects; a Textual TUI browses them offline; a small set of write operations (comment, link, feature-flags) lets you push back without leaving the terminal. Local tags and alerts surface related issues as you browse — the coworker's "logos need light/dark alternatives" issue pops up as a card when you open the PO's "add logo to layout" ticket, ready to link in one keystroke.

Deliberately narrow: this is a personal tool, not a team dashboard.

Install

uv sync
uv run tendril config init          # walks through URL, email, API token
uv run tendril whoami               # verifies auth

Config lives at ~/.config/tendril/config.toml; the API token in the OS keyring; the cache at ~/.local/share/tendril/tendril.db. See docs/config.md for token rotation, manual TOML editing, and per-instance settings.

First sync

uv run tendril sync project MMINT   # pulls every issue in MMINT into the cache (paginated)
uv run tendril show MMINT-42        # prints an issue from the cache
uv run tendril sync incremental     # from then on, refreshes only what changed

See docs/sync.md for sync issue (single-issue fallback), the rename-migration behavior, and the intended workflow in detail.

Watchlist

A marker layer on top of the cache — adding a key never touches JIRA. Watchlisted rows show a marker in the TUI overview and render in the accent color.

See docs/watchlist.md for watchlist add, remove, list, and the TUI shortcuts.

TUI

Run with no subcommand:

uv run tendril

Two screens plus a global search.

Overview — a table of every cached issue, with a column marking watchlisted rows.

key binding
a add issue key to watchlist
d drop watchlist marker on highlighted row
w toggle watchlist-only filter
o toggle open-only filter (hides done statuses)
s run incremental sync
r reload from cache
open issue detail
q quit

Issue detail — metadata plus tabs (Description, Comments, Links, Flags) on the left, a Surfaces panel on the right (7:3 split).

key binding
r refetch this issue from JIRA
c add a comment (ctrl+s in the modal to submit)
l link this issue to another key
x remove the highlighted link (Links tab only)
f edit the feature-flags custom field
t edit local tags on this issue
A toggle the alert marker on this issue
s focus the Surfaces panel
p open this issue's parent
(on a surface card) open the link modal
esc back

Global — works from any screen:

key binding
/ search cached issues by key or summary
ctrl+p command palette (Sync project… + one per synced project)

Tags and alerts

Two local layers on top of the cache. Neither is pushed to JIRA.

  • Tags are free-form labels on cached issues (logo, branding, deal-placement, …).
  • Alerts mark an issue as one you want reminded of. When you open a different cached issue, alerts that share at least one tag surface as cards on the right-hand Surfaces panel. Press on a card to link the two issues.

The trigger is tag overlap — there are no rule files.

See docs/tags-and-alerts.md for the full CLI (tag add/remove/set/list, alert add/remove/list), the --json output shape for LLM pipelines, and the TUI shortcuts.

Feature flags

The f binding in the TUI is only useful once you set the custom-field id for feature flags:

[fields]
feature_flags = "customfield_10457"

The field is assumed to be a JIRA labels-type custom field (payload shape ["flag_a", "flag_b"]). Empty submit clears all flags. Full config layout: docs/config.md.

Design notes

  • Sync fills the cache; the watchlist, tags, and alerts sit on top. Separate tables, each opt-in.
  • Every write refetches the touched issue. No local mutation bypasses JIRA — the cache stays honest. Tags and alerts are local-only and never touch JIRA.
  • Whole-project sync only. Per-issue single fetches exist (sync issue KEY) but are a fallback; the intended workflow is sync project KEY once, then sync incremental from there.
  • JIRA rename resilience. If JIRA has moved an issue to another project, sync issue OLDKEY follows the redirect, cache is upserted under the new key, and any watchlist entry for the old key is migrated.
  • No Alembic yet. Base.metadata.create_all() plus a schema_version row carries us here. Alembic joins when the first breaking schema change lands.

Testing

uv run pytest

Unit + Textual Pilot smoke tests. Live integration tests (real JIRA calls against a sandbox) are gated:

TENDRIL_LIVE=1 TENDRIL_LIVE_ISSUE=SANDBOX-1 uv run pytest tests/integration

Layout

src/tendril/
  cli.py            typer app; console_script `tendril`
  config.py         XDG paths, TOML load/save, keyring
  db/               SQLAlchemy 2 models, engine, schema init
  jira/             thin atlassian-python-api wrapper + DTOs
  sync/             fetch → normalize → upsert; sync_issue, sync_project, incremental
  operations/       single write layer (JIRA write → refetch)
  alerts/           local-only tags + alerts; matcher for the Surfaces panel
  tui/              Textual app, screens, modals, command-palette provider

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tendril_jira-1.0.0.tar.gz (46.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tendril_jira-1.0.0-py3-none-any.whl (59.8 kB view details)

Uploaded Python 3

File details

Details for the file tendril_jira-1.0.0.tar.gz.

File metadata

  • Download URL: tendril_jira-1.0.0.tar.gz
  • Upload date:
  • Size: 46.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.23

File hashes

Hashes for tendril_jira-1.0.0.tar.gz
Algorithm Hash digest
SHA256 6e4d1f8c259da5746543e4990dd14f51b3f5c165628e1d9ce770b86ad1061159
MD5 5f4ad84dac7845908e10c694ae6b423f
BLAKE2b-256 637725267f2b949084ba3091be9ec7163ba8c217729ceae299115d63fbdd728e

See more details on using hashes here.

File details

Details for the file tendril_jira-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for tendril_jira-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 96c8b0497b5ff99f5595b14e155b4b40c0dc62536e6f25ae10d225fbae2b6a1e
MD5 59892f8c56bd9c2bdf37b1b2f17bc653
BLAKE2b-256 f0be7914f863a54b249affdfe501d6623e0fb4c8db4fce3a96a8a3a458928ce6

See more details on using hashes here.

Release history Release notifications | RSS feed

1.2.2

2 files

1.2.1

2 files

1.2.0

2 files

1.1.0

2 files

This release

1.0.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page