Bug Description
I found a real sqlite connection leak in the kanban specify helpers.
hermes_cli.kanban_specify currently uses with kb.connect() as conn: in helper paths like list_triage_ids() and specify_task().
For sqlite3.Connection, that context-manager pattern does not close the connection. It only manages the transaction scope. As a result, repeated calls leak file descriptors.
This becomes user-visible in long-lived processes that invoke kanban commands repeatedly, including the gateway /kanban command path, which routes through run_slash in-process.
What I expected instead was for these helpers to always close their sqlite connections explicitly.
Steps to Reproduce
- Start from current
main
- In a single Python process, set a temporary
HERMES_HOME
- Call
hermes_cli.kanban_specify.list_triage_ids() repeatedly
- Watch the open fd count grow
Minimal repro I used:
import os, tempfile
os.environ["HERMES_HOME"] = tempfile.mkdtemp(prefix="hermes_fdleak_spec_")
from hermes_cli import kanban_db as kb
from hermes_cli import kanban_specify as ks
conn = kb.connect()
conn.close()
base = len(os.listdir("/proc/self/fd"))
for _ in range(50):
ks.list_triage_ids()
after = len(os.listdir("/proc/self/fd"))
print({"base": base, "after": after, "delta": after - base})
### Expected Behavior
Repeated calls to these kanban specify helpers should not leave sqlite connections open or grow the process fd count over time.
### Actual Behavior
The fd count grows with repeated calls.
In my repro on current main:
`{'base': 5, 'after': 52, 'delta': 47}`
After patching the helper to close connections explicitly, the same repro becomes:
`{'base': 5, 'after': 5, 'delta': 0}`
### Affected Component
CLI (interactive chat)
### Messaging Platform (if gateway-related)
_No response_
### Debug Report
```shell
Report https://paste.rs/NPzLw
agent.log https://paste.rs/lSpan
Operating System
Ubuntu on WSL2 (Windows 11)
Python Version
Python 3.12.3
Hermes Version
Hermes Agent v0.14.0 (2026.5.16)
Additional Logs / Traceback (optional)
This is a steady-state resource leak rather than an immediate traceback.
The practical failure mode is fd exhaustion in long-lived processes that keep invoking these helpers, which can eventually surface as sqlite open failures or broader `too many open files` symptoms.
Root Cause Analysis (optional)
hermes_cli.kanban_specify uses with kb.connect() as conn:.
kb.connect() returns a sqlite3.Connection. In sqlite, with conn: does not close the connection on exit; it only commits or rolls back the transaction.
So these helpers leak a connection each time they run unless the process exits immediately afterward.
Proposed Fix (optional)
Wrap these helper connections with contextlib.closing(kb.connect()) so the sqlite handle is always closed.
I also prepared regression coverage that uses a sqlite-like fake connection whose context manager does not call close(), to make sure the helpers explicitly close their connections.
Are you willing to submit a PR for this?
Bug Description
I found a real sqlite connection leak in the kanban specify helpers.
hermes_cli.kanban_specifycurrently useswith kb.connect() as conn:in helper paths likelist_triage_ids()andspecify_task().For
sqlite3.Connection, that context-manager pattern does not close the connection. It only manages the transaction scope. As a result, repeated calls leak file descriptors.This becomes user-visible in long-lived processes that invoke kanban commands repeatedly, including the gateway
/kanbancommand path, which routes throughrun_slashin-process.What I expected instead was for these helpers to always close their sqlite connections explicitly.
Steps to Reproduce
mainHERMES_HOMEhermes_cli.kanban_specify.list_triage_ids()repeatedlyMinimal repro I used:
Operating System
Ubuntu on WSL2 (Windows 11)
Python Version
Python 3.12.3
Hermes Version
Hermes Agent v0.14.0 (2026.5.16)
Additional Logs / Traceback (optional)
Root Cause Analysis (optional)
hermes_cli.kanban_specifyuseswith kb.connect() as conn:.kb.connect()returns asqlite3.Connection. In sqlite,with conn:does not close the connection on exit; it only commits or rolls back the transaction.So these helpers leak a connection each time they run unless the process exits immediately afterward.
Proposed Fix (optional)
Wrap these helper connections with
contextlib.closing(kb.connect())so the sqlite handle is always closed.I also prepared regression coverage that uses a sqlite-like fake connection whose context manager does not call
close(), to make sure the helpers explicitly close their connections.Are you willing to submit a PR for this?