daemon-forensics · v1.4.0 · 2026-09-09 · sha256 72b59dd930416fbe

daemon-forensics v1.4.0A

Immutable. This exact content is served forever at /api/v1/blob/72b59dd930416fbe.

---
name: daemon-forensics
description: >
  Nested daemon-manual reference for durable run artifacts, state/result
  inspection, transcripts, token ledgers, and interpreting exit 143/SIGTERM.
version: 1.4.0
last_changed_at: 2026-09-08T00:00:00Z
related_files:
- src/lingtai/tools/daemon/manual/SKILL.md
- src/lingtai/tools/daemon/run_dir.py
- src/lingtai/tools/daemon/runtime.py
maintenance: |
  Tracks the daemon artifact-forensics topic; update when run files or
  terminal/error reporting changes.
---

# Daemon Forensics Reference

Read this when a run needs evidence beyond the notification or `check` result.
The run directory is durable evidence, not a disposable workspace.

## Durable run layout

New tasks get `daemons/em-<id>/` under the parent working directory (or the
standalone state root). Returned id, `daemon.json.run_id`, and folder name
identify the same new run; legacy ids can be ambiguous, so prefer exact run ids.
`reclaim` cancels all running manager-owned work but leaves its files. A molt clears conversation
context; it does not wipe durable stores or run folders.

```text
daemons/em-<id>/
├── daemon.json             # identity, state, call parameters, previews
├── artifacts.json          # metadata-only manifest, written at terminal time
├── result.txt              # full result or bounded error text
├── .prompt                 # constructed system prompt
├── history/chat_history.jsonl
└── logs/{events,token_ledger}.jsonl
```

`artifacts.json` contains run-relative `{path, size, mtime, role}` entries plus
`state`, `result_path`, `error_path`, `artifacts_total`, and `truncated`. It
contains paths and metadata, never file contents. `check` prefers this
manifest and can produce a bounded fallback for live or legacy runs. Avoid
secret-bearing filenames.

## Disclosure order

1. Read the terminal notification and call `daemon(action="check", input={"id": "<run_id>"})`.
2. Open its durable `result_path` or `error_path`; use `.prompt` when the task
   or selected context needs verification.
3. Read `logs/events.jsonl`, `history/chat_history.jsonl`, or
   `logs/token_ledger.jsonl` only for the specific forensic question.

For a known legacy run, `check` or direct inspection may be needed even when
`list` omits it. An omitted ledger item is not proof of deletion or failure.

## State and failure fields

In `daemon.json`, inspect `state` (`running`, `done`, `failed`, `cancelled`,
`timeout`), `current_tool`, `turn`, `tool_call_count`, `last_output_at`,
`result_preview`, `result_path`, `error`, and `elapsed_s`. LingTai token totals
are in `tokens`; external CLI usage is separate and remains in run artifacts.
Native transcripts record task, assistant, tool-result, and follow-up entries;
CLI model transcripts may instead live in the vendor session store. CLI usage
is `cli_tokens`, not parent/kernel token-ledger spend; never sum both lanes as
if they were comparable. Read JSONL line by line, not as one JSON document.

## Suspected stall

A concrete progress question permits a bounded `check` before completion.
Compare state, tool/count, recent events and output timestamps over a meaningful
interval for this task; native transcript progress and CLI `last_output_at` are
different signals. A slow tool or quiet model is not by itself a stall. Do not
run completion-poll loops, infer failure from silence, or reclaim on a hunch.
If intervention is warranted, confirm its authority and **all** affected runs.
Normal waiting relies on terminal notifications; do not add a recurring timer.
Only if completion delivery itself is unverified and work remains pending, use
the Shell manual's one-shot wake route, sized to the expected task duration;
inspect progress on that wake instead of repeatedly re-arming it.

## Exit 143 / SIGTERM

A shell-style 143 usually represents `128 + SIGTERM`; a direct subprocess may
report `-15`. Neither proves a failed assertion, the sender, or even signal
termination by itself (a program can explicitly exit 143). Match the actual
supervisor receipt and events. A watchdog, reclaim, host shutdown, or the task's
own process tree may be responsible; a timeout or turn-limit failure need not
produce 143. Do not blame parent molt: context shedding is not cancellation.

Before rerunning, inspect `daemon.json`, physical `result.txt`, and recent events;
partial work may already suffice. Match configured limits and explicit cancel
records. If continuation is needed, keep the old artifacts and re-check scope
and execution-body instructions: native terminal runs cannot resume, while some
CLI runs support `ask`. No automatic rerun or model/backend switch is authorized.
Report the observed termination and evidence-backed cause, or say it is unknown.

## Safety boundary

Inspection is read-only. Do not infer liveness from one quiet snapshot, delete
run evidence while diagnosing, print credential values, or treat a partial
143 result as a reason to widen the parent task. Consent-gated footprint and
deletion procedure belongs in `../cleanup/SKILL.md`.