MoonshotAI / MoonshotAI/kimi-code
Background tasks show as running in UI but disappear from /tasks after a non-graceful exit
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
- Start a long-running background task in a session (e.g. a shell command that sleeps).
- 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.
- Reopen the app and look at the session in the web/desktop UI: the task still shows as running.
- In the CLI,
/tasks(or the REST endpointGET /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) recordstask.startedas a durable event, buttask.terminatedis 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 baretask.startedand notask.terminatedis reconstructed forever asstate: '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:
- 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'). - 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 baretask.startedevents in the wire log.
Both changes are scoped to the server side; the CLI and live-session paths need no changes.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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