# Pulse

**Detect when processes are alive but not doing meaningful work.**

Traditional monitoring asks: "Is this process running?" Pulse asks: "When did this process last produce something useful?"

## Install

```bash
pip install pulse-monitor
```

Or run directly:

```bash
python -m pulse check
```

## Quick Start

```bash
# Create example config
pulse init

# Edit pulse.yaml with your vital signs
# Then check everything:
pulse check
```

## Configuration

Pulse uses `pulse.yaml` (with PyYAML) or `pulse.json` (no dependencies).

```yaml
vitals:
  - name: "Trading Bot"
    checks:
      - type: file_freshness
        path: "data/trades.json"
        max_age: "2h"
      - type: json_key_changed
        path: "data/trades.json"
        key: "trade_count"
        max_age: "24h"

  - name: "Content Engine"
    checks:
      - type: file_freshness
        path: "data/content_state.json"
        max_age: "8h"
      - type: log_entry
        path: "logs/engine.log"
        pattern: "cycle completed"
        max_age: "6h"
```

## Check Types

### `file_freshness`

Checks if a file was modified within `max_age`.

| Field    | Required | Description                    |
|----------|----------|--------------------------------|
| path     | Yes      | File path (relative to config) |
| max_age  | Yes      | Duration: `30s`, `5m`, `2h`, `1d` |

### `json_key_changed`

Checks if a specific key in a JSON file has changed value since the last check. Stores previous values in `.pulse_state.json`.

| Field    | Required | Description                         |
|----------|----------|-------------------------------------|
| path     | Yes      | JSON file path                      |
| key      | Yes      | Dotted key path (e.g. `stats.count`)|
| max_age  | Yes      | Max time since last value change    |

### `log_entry`

Checks if a regex pattern appears in a log file within `max_age`.

| Field    | Required | Description                    |
|----------|----------|--------------------------------|
| path     | Yes      | Log file path                  |
| pattern  | Yes      | Regex pattern to search for    |
| max_age  | Yes      | Max age of matching entry      |

### `process_output`

Runs a command and checks exit code and/or output.

| Field          | Required | Description                          |
|----------------|----------|--------------------------------------|
| command        | Yes      | Shell command to run                 |
| exit_code      | No       | Expected exit code (default: 0)      |
| output_pattern | No       | Regex to match against stdout        |
| timeout        | No       | Seconds before timeout (default: 30) |

## CLI Usage

```bash
# Run all checks (exit 0=healthy, 1=issues, 2=config error)
pulse check

# JSON output for piping to other tools
pulse check --json

# Check a single vital
pulse check --name "Trading Bot"

# Use specific config file
pulse -c /path/to/pulse.yaml check

# Create example config
pulse init
pulse init --json    # JSON format instead of YAML
pulse init --force   # Overwrite existing

# Show check history
pulse history
pulse history -n 20
pulse history --json
```

## Output

```
[  OK] Trading Bot — All 2 checks passed (last activity: 15m ago)
[WARN] Content Engine — 1/2 checks failed
       ✗ log_entry: "cycle completed" last seen 14h ago (max: 6h)
       ✓ file_freshness: data/content_state.json updated 2h ago
[CRIT] Evolution Engine — All checks failed (last activity: 3d ago)
```

Severity levels:
- **OK** — All checks pass
- **WARN** — Some checks fail
- **CRIT** — All checks fail

## Duration Format

Supports: `30s`, `5m`, `2h`, `1d`, `1w`. Combined forms: `1d12h`, `2h30m`.

## Exit Codes

| Code | Meaning              |
|------|----------------------|
| 0    | All checks passed    |
| 1    | One or more failures |
| 2    | Config/usage error   |

## License

MIT
