Skip to content

feat: add Kilo and Pi agent watchers#43

Open
devopstales wants to merge 4 commits into
Ataraxy-Labs:mainfrom
devopstales:main
Open

feat: add Kilo and Pi agent watchers#43
devopstales wants to merge 4 commits into
Ataraxy-Labs:mainfrom
devopstales:main

Conversation

@devopstales
Copy link
Copy Markdown

Summary

  • Add built-in support for Kilo CLI sessions through a new KiloAgentWatcher.
  • Register and export the watcher from the runtime/server startup path.
  • Update docs to list Kilo support and document KILO_DB_PATH.
  • Refresh built-in watcher docs so the existing Pi watcher is also reflected consistently.

Details

The Kilo watcher polls the Kilo CLI SQLite database at ~/.local/share/kilo/kilo.db, or KILO_DB_PATH when set, using bun:sqlite in read-only mode.

It maps Kilo sessions back to opensessions mux sessions through each row's working_directory, then derives status from the head message_nodes entry referenced by
main_chain_id.

Supported status handling includes:

  • running for user/tool messages, streaming assistant messages, and assistant tool calls
  • done for assistant messages with finish_reason=stop
  • error for finish_reason=error
  • interrupted for Kilo interrupt marker messages
  • stale when a running session stops advancing for 15 seconds

The watcher also skips hidden sessions, ignores old inactive sessions, emits title updates, and reopens the database after read failures.

Testing

  • cd packages/runtime && bun test test/kilo.test.ts

Result: 30 tests passing.

Copy link
Copy Markdown

@inspect-review inspect-review Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inspect review

Triage: 85 entities analyzed | 0 critical, 0 high, 12 medium, 73 low
Verdict: standard_review

Findings (2)

  1. [low] determineStatus() references msg.data even though MessageData has no data field. In packages/runtime/src/agents/watchers/kilo.ts, determineStatus contains if (typeof msg?.data === "string") { const parsed = JSON.parse(msg.data); msg = parsed; }, but MessageData is defined without data. This is a real type/logic mismatch (likely confusion between MessageRow vs parsed MessageData) and the branch is effectively dead under correct typing.
  2. [low] poll() contains a copy-paste fallback that repeats the exact same SQL query, so it cannot recover from any schema/query failure. In packages/runtime/src/agents/watchers/kilo.ts, the catch block labeled 'Try alternative query for Kilo schema' executes the identical SELECT id, title, directory, time_updated FROM session WHERE time_updated > ? ORDER BY time_updated DESC again, making the fallback useless and misleading.

Reviewed by inspect | Entity-level triage found 0 high-risk changes

@Palanikannan1437 Palanikannan1437 self-requested a review May 18, 2026 20:05
- Remove unreachable `msg.data` string-parsing branch in
  determineStatus(). The caller (readSessionStatus) already parses
  the JSON before calling this function, so the branch could never
  fire and conflicted with the MessageData type contract.

- Remove duplicate fallback query in poll() that ran the identical
  SQL on failure — it could never succeed where the first attempt
  failed. On query error, just close the DB handle and return so
  the next poll cycle reopens it.
@rs545837
Copy link
Copy Markdown
Member

rs545837 commented May 24, 2026

Hey, nice work on this, the schema docs and test coverage are solid. Two small things to clean up before we merge:

1. Dead branch in determineStatus() (lines 168-175)

The typeof msg?.data === "string" check can never fire. readSessionStatus() already does JSON.parse(lastMsg.data) before calling determineStatus(msgData), so by the time we get here it's always a parsed MessageData object, never a raw DB row. It also doesn't match the function's type signature (MessageData | null), which doesn't have a data field. Safe to remove the whole block.

2. Duplicate fallback query in poll() (lines 317-328)

The inner catch runs the same SQL as the outer try, if it failed once it'll fail the same way again. Looks like a copy-paste leftover from when there was going to be an alternative query. Can collapse to a single try/catch that closes the DB handle on failure.

Both are just dead code, not bugs. The watcher logic itself is correct.

Regenerate the three snapshot files to include the new
`l lazydiff  L new window` footer line added to the renderer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants