MoonshotAI / MoonshotAI/kimi-code

Background tasks show as running in UI but disappear from /tasks after a non-graceful exit

Open
#3,924 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7.5k
Forks
1.2k
Avg merge
11h 53m
Merged PRs (30d)
350

Description

Bug: background tasks stuck as "running" in UI after the app exits, while /tasks can no longer find them

Repro
  1. Start a long-running background task in a session (e.g. a shell command that sleeps).
  2. Kill the app process abruptly (or let the machine reboot / the process die without graceful shutdown) — any exit path that does not go through the graceful session-close flow.
  3. Reopen the app and look at the session in the web/desktop UI: the task still shows as running.
  4. In the CLI, /tasks (or the REST endpoint GET /api/v1/sessions/{id}/tasks) reports nothing for that session.
Root cause

Task state lives in several places with no reconciliation between them:

  • The live registry (AgentTaskService) is scoped to the agent/session and disappears when the session is destroyed — so the CLI/cold REST endpoint legitimately see no tasks.
  • The wire log (wire.jsonl) records task.started as a durable event, but task.terminated is only written on the graceful-exit path (removeManaged -> stopAllOnExit -> flush). On a crash/kill the termination event is missing.
  • The UI reads tasks from the transcript projection. For a cold session this is rebuilt purely from wire.jsonl, so a task with a bare task.started and no task.terminated is reconstructed forever as state: 'running'.

Result: two views of the same task that permanently disagree — "running" in the UI, empty in /tasks.

Suggested fix

Two small, storage-layer-only changes:

  1. kap-server cold transcript read (readColdSnapshot): a cold session's owner process is gone by definition, so any non-terminal task in the folded snapshot should be rewritten to a terminal state ('lost').
  2. AgentTaskService.dispose: settle non-terminal entries to killed (reason: session closed) and persist, mirroring the graceful-exit path, so a hard kill does not leave bare task.started events in the wire log.

Both changes are scoped to the server side; the CLI and live-session paths need no changes.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the kap-server readColdSnapshot path and AgentTaskService.dispose, then trace the existing removeManaged → stopAllOnExit → flush flow and wire.jsonl task events. Verify that cold snapshots rewrite non-terminal tasks to lost, while disposal persists non-terminal entries as killed with the session-closed reason, and confirm the UI and /tasks views agree after an abrupt exit.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.