Metadata-Version: 2.4
Name: agent-coroner
Version: 0.1.0
Summary: Artifact contracts, silent-failure detection, and LLM autopsy reports for unattended AI agents
Project-URL: Homepage, https://github.com/Chikoku-NEKO/agent-coroner
Project-URL: Issues, https://github.com/Chikoku-NEKO/agent-coroner/issues
Author: Chikoku-NEKO
License: MIT
License-File: LICENSE
Keywords: ai-agents,claude,cron,monitoring,postmortem,silent-failure
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.10
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# agent-coroner

Artifact contracts, silent-failure detection, and LLM autopsy reports for unattended AI agents.

Your cron-scheduled agent ran fine — exit code 0 — but the weekly report it was
supposed to write never appeared. Nothing alerted you. That's a silent failure,
and it's the failure mode of unattended agents. agent-coroner watches the
*artifacts* your jobs promise to produce, notifies you when a promise is broken,
and (optionally) dispatches a read-only Claude "coroner" to write a postmortem
explaining why.

## How it works

1. **Contracts** — declare what each job must produce (`contracts.yaml`)
2. **Checker** — a fast, deterministic, LLM-free check: file exists, fresh enough, big enough, passes your verify command. Run it from cron / Task Scheduler.
3. **Autopsy** — only when a contract is violated, `claude -p` is launched read-only (`Read,Grep,Glob`) to diagnose the logs and write a 4-section postmortem (facts / hypotheses / verification steps / prevention). If the autopsy itself fails, the violation notification still goes out — detection never depends on the LLM.

No self-healing by design: the coroner examines the scene, it never touches it.

## Install

    uv tool install agent-coroner   # or: pip install agent-coroner

Requires the `claude` CLI on PATH only for autopsies; check/status/unread work without it.

## Quick start

`contracts.yaml`:

```yaml
jobs:
  weekly-report:
    schedule: "FRI 08:30"
    grace_minutes: 60
    artifacts:
      - path: "reports/weekly-*.md"
        max_age_hours: 192
        min_bytes: 500
    logs: "run.log"
```

Run it before the artifact exists (or after it's gone stale) and the checker
reports a `missing` violation with a non-zero exit code:

```
$ coroner check --config contracts.yaml --no-autopsy
[coroner] 1 violation detected
- weekly-report / reports/weekly-*.md: missing (no file matches 'reports/weekly-*.md' under <contracts-dir>)
[coroner] 1 violation detected
- weekly-report / reports/weekly-*.md: missing (no file matches 'reports/weekly-*.md' under <contracts-dir>)
$ echo $?
1
```

(The message appears twice here because no `notify` command is configured: the
checker prints its own progress line, then falls back to printing the same
message a second time as the "notification". Set `notify` — see below — to
route it somewhere else instead of stdout twice.)

Once `reports/weekly-*.md` exists, is fresh, and clears `min_bytes`, the same
command prints `weekly-report: ok` and exits `0`.

Register `coroner check` on a schedule:

```powershell
schtasks /create /tn "coroner-check" /tr "coroner check --config C:\path\to\contracts.yaml" /sc daily /st 09:00
```

```cron
*/15 * * * * coroner check --config /path/to/contracts.yaml >> /var/log/coroner.log 2>&1
```

## Contract reference

- `lang` — top-level, `"en"` (default) or `"ja"` — language of autopsy postmortem section headers. Any other value raises a config error at load time.
- `jobs.<name>` — one entry per unattended job; the key is the job name used in state, notifications, and postmortem filenames.
- `schedule` — free-text metadata only (e.g. `"FRI 08:30"`), not parsed or enforced by the checker; it exists for humans and for the autopsy prompt's job-definition context.
- `grace_minutes` — added to `max_age_hours` (as minutes) before an artifact counts as stale. Default `0`.
- `workdir` — directory artifact/log globs are resolved against. Default: the directory containing `contracts.yaml`.
- `artifacts` — list of rules, each checked independently; a job can have any number:
  - `path` — a glob relative to `workdir`; the newest matching file (by mtime) is evaluated.
  - `max_age_hours` — if set, the newest match's age (plus `grace_minutes`) must not exceed this or the artifact is `stale`. Omit to skip the freshness check.
  - `min_bytes` — minimum file size in bytes; below this the artifact is `too_small`. Default `1`.
  - `verify` — optional shell command run against the newest match; `{path}` is substituted with the file's full path before the command runs via `shell=True` in `workdir`. A non-zero exit is a `verify_failed` violation. **On Windows, quote it** — an unquoted `{path}` containing spaces breaks the command line: use `verify: "python check.py \"{path}\""`, not `verify: "python check.py {path}"`.
  - Violation types in order of the check: `missing` → `stale` → `too_small` → `verify_failed`.
- `logs` — optional glob for the job's log file; only used to build the autopsy prompt's log-tail evidence, not checked itself.
- `notify` — optional shell command run via `shell=True` when a violation fires. Two substitution tokens, mutually compatible:
  - `{message}` — the whole notification text flattened to one line: double quotes become single quotes, newlines become `"; "`. Fragile for anything beyond a simple one-liner.
  - `{message_file}` — the full, unflattened, multi-line message is written to a temporary UTF-8 text file and this token is replaced with that file's path; the file is deleted after the notify command runs. This is the reliable way to pass a multi-line report through a shell command, e.g. `powershell -NoProfile -Command "Get-Content -Raw '{message_file}' | Write-Host"`.
  - If `notify` is omitted, the message is printed to stdout instead.

## Claude Code plugin

    /plugin marketplace add Chikoku-NEKO/agent-coroner
    /plugin install agent-coroner@agent-coroner-marketplace

- `/coroner-status` — runs `coroner status` and summarizes which jobs are ok, which have violations, and their recent ok-rate; tells you to `uv tool install agent-coroner` if the CLI isn't found.
- `/autopsy <job-name>` — runs `coroner autopsy --job <job-name>` on demand and presents the resulting postmortem's four sections, or reports that the job's contract is currently satisfied.
- A `SessionStart` hook runs `coroner unread` at the start of every Claude Code session so unread postmortems (any generated since your last acknowledgment) surface automatically instead of sitting silently in the postmortems directory.

## Exit codes / Security notes / License

- Exit codes: `0` = all contracts satisfied, `1` = one or more violations (or a job's check crashed), `2` = config error (bad/missing `contracts.yaml`, unknown `--job`).
- `verify` and `notify` are user-defined shell commands executed with `shell=True` — only point `--config` at contract files you trust. A malicious `contracts.yaml` can run arbitrary commands on your machine.
- MIT License — see [LICENSE](LICENSE).
