Metadata-Version: 2.4
Name: openclaw-cron-lint
Version: 0.1.0
Summary: Lint OpenClaw cron job configurations for risky delivery and prompt patterns.
Author: OpenClaw Cron Lint Contributors
License-Expression: MIT
Project-URL: Homepage, https://github.com/pfrederiksen/openclaw-cron-lint
Project-URL: Repository, https://github.com/pfrederiksen/openclaw-cron-lint
Project-URL: Issues, https://github.com/pfrederiksen/openclaw-cron-lint/issues
Keywords: openclaw,cron,lint,cli
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# openclaw-cron-lint

`openclaw-cron-lint` is a small CLI that checks OpenClaw cron job configuration quality before a scheduled run causes confusing delivery behavior.

It is intentionally focused on OpenClaw cron jobs. It is not a general JSON linter, cron expression validator, or prompt-quality grader.

## Install

From this repository:

```bash
python3 -m pip install -e .
```

Run the CLI:

```bash
openclaw-cron-lint /root/.openclaw/cron/jobs.json
```

You can also run it without installing:

```bash
PYTHONPATH=src python3 -m openclaw_cron_lint fixtures/jobs-risky.json
```

## What It Checks

Current rules:

| Rule | Severity | Check |
| --- | --- | --- |
| `OC001` | error | `sessionTarget: isolated` with prompt instructions to use the message tool directly |
| `OC002` | error/warning | payload kind incompatible or suspicious with the configured session target |
| `OC003` | error | announce delivery missing `channel` or `to` |
| `OC004` | warning | `delivery.mode: none` combined with prompt instructions that imply user-visible messaging |
| `OC005` | error | contradictory prompt instructions such as "use the message tool" and "do not use the message tool" |
| `OC006` | warning | stateful or periodic jobs missing `factKey` |
| `OC007` | warning | suspicious `NO_REPLY` guidance when content is also supposed to be returned or delivered |
| `OC008` | warning | expensive-looking agent jobs missing a timeout |
| `OC009` | info | duplicated or overly similar prompts |
| `OC010` | warning | isolated jobs assuming a current or main session |

Each finding includes the job name, job id, severity, rule id, explanation, and recommended fix.

## Examples

Human-readable output:

```bash
openclaw-cron-lint fixtures/jobs-risky.json
```

JSON output:

```bash
openclaw-cron-lint fixtures/jobs-risky.json --json
```

Markdown report:

```bash
openclaw-cron-lint fixtures/jobs-risky.json --markdown
```

Fail CI only on high-severity findings:

```bash
openclaw-cron-lint fixtures/jobs-risky.json --fail-on high
```

`high` is accepted as an alias for `error`, because the linter uses the OpenClaw severities `info`, `warning`, and `error`.

Run or skip selected rules:

```bash
openclaw-cron-lint fixtures/jobs-risky.json --only OC001 --only OC003
openclaw-cron-lint fixtures/jobs-risky.json --ignore OC009
```

Directory input is supported for future extension. The linter currently scans `*.json` files in the directory:

```bash
openclaw-cron-lint fixtures/
```

## Configuration Shape

The loader accepts:

- a JSON array of job objects
- an object with a `jobs` array
- a single job object

Rules are schema-tolerant and look for common OpenClaw fields such as:

- `id`, `jobId`, `name`
- `prompt`, `instructions`, `systemPrompt`
- `sessionTarget`
- `payload.kind`
- `delivery.mode`, `delivery.channel`, `delivery.to`
- `factKey`
- `timeoutSeconds`, `maxRuntimeSeconds`
- `cron`, `schedule`, `interval`

## Limits Of Static Linting

This tool does not execute jobs, connect to OpenClaw, inspect live sessions, or prove delivery will succeed. It flags patterns that are usually risky or contradictory from static configuration alone.

False positives are expected when a deployment uses custom payload kinds, custom delivery adapters, or prompt conventions that the linter does not yet know. Use `--ignore RULE` for local policy exceptions.

## Extending Rules

Rules live in `src/openclaw_cron_lint/rules.py`.

To add a rule:

1. Add a function that accepts `Sequence[JobContext]` and returns `List[Finding]`.
2. Use the `finding(...)` helper so output stays consistent.
3. Register the function in the `RULES` dictionary with a stable rule id.
4. Add focused tests under `tests/`.
5. Document the rule in this README.

Keep rules specific to OpenClaw cron configuration quality. Avoid adding broad JSON style rules or generic prompt linting unless they directly affect cron delivery behavior.

## Development

Run tests:

```bash
PYTHONPATH=src python3 -m unittest discover -s tests
```

## Publishing

Releases are published to PyPI by the `Publish` GitHub Actions workflow. It matches the release pattern used by `agent-scope-diff`:

- package version is read from `pyproject.toml`
- release tags must be named `vX.Y.Z`
- the tag version must match the package version
- distributions are built with `python -m build`
- `twine check` runs before upload
- upload uses the repository secret `PYPI_API_TOKEN`

To release `0.1.0`:

```bash
git tag v0.1.0
git push origin v0.1.0
```
