Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@
"name": "agentrust-io"
},
"license": "Apache-2.0"
},
{
"name": "agentrust-scheduled-agents",
"source": "./scheduled-agents",
"description": "Agent-integrity for Claude Code scheduled agents: fingerprint routine specs and auto-run hooks, and check nothing changed about what runs without you watching since your approved baseline.",
"version": "0.1.0",
"author": {
"name": "agentrust-io"
},
"license": "Apache-2.0"
}
]
}
54 changes: 54 additions & 0 deletions .github/workflows/scheduled-agents-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: scheduled-agents tests

on:
pull_request:
paths:
- "scheduled-agents/**"
- ".github/workflows/scheduled-agents-tests.yml"
push:
branches: [main]
paths:
- "scheduled-agents/**"
- ".github/workflows/scheduled-agents-tests.yml"

permissions:
contents: read

jobs:
# The SessionStart hook and drift check must work with the standard library
# alone. This job installs no crypto packages, so the signing tests skip and
# any accidental dependency on them fails the build.
stdlib:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.12"
- name: Run stdlib-only tests (no crypto packages)
working-directory: scheduled-agents
run: |
pip install pytest
python -m pytest tests -q

# Full suite including the signing / verification tests, which need the crypto
# packages from requirements.txt.
signing:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.python-version }}
- name: Run full suite (with crypto packages)
working-directory: scheduled-agents
run: |
pip install pytest -r requirements.txt
python -m pytest tests -q
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ TRACE only works as a standard if it is genuinely neutral. Integrations are list
|---|---|---|---|
| [claude-code](claude-code/) | agentrust-io | agent-manifest, trace | community |
| [agentrust-codex](plugins/agentrust-codex/) | agentrust-io | agent-manifest, trace | community |
| [scheduled-agents](scheduled-agents/) | agentrust-io | trace | community |

## Community

Expand Down
11 changes: 11 additions & 0 deletions scheduled-agents/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "agentrust-scheduled-agents",
"description": "Agent-integrity for Claude Code scheduled agents: fingerprint routine specs and auto-run hooks, and check nothing changed about what runs without you watching since your approved baseline.",
"version": "0.1.0",
"author": {
"name": "agentrust-io"
},
"homepage": "https://github.com/agentrust-io/integrations/tree/main/scheduled-agents",
"repository": "https://github.com/agentrust-io/integrations",
"license": "Apache-2.0"
}
9 changes: 9 additions & 0 deletions scheduled-agents/PRIVACY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Privacy

The AgenTrust scheduled-agents plugin collects and transmits no personal data.

It runs locally as a Claude Code plugin. It processes only your local routine specs and Claude configuration, entirely on your machine, and sends no telemetry, analytics, or usage data to agentrust-io, OPAQUE, or any third party. There is no account, login, or tracking, and no cookies or background network calls.

It records names and fingerprints only (routine, tool, MCP, and hook-command names, and SHA-256 hashes of prompts and settings). It never stores secrets, never reads your credentials file, and never records a hook command's output. The drift baseline and any TRACE record are written to files on your machine; nothing is sent anywhere. Signing uses a local key whose private half never leaves the machine.

Uninstalling removes it completely. Questions or corrections: https://github.com/agentrust-io/integrations/issues
115 changes: 115 additions & 0 deletions scheduled-agents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# AgenTrust for Claude Code scheduled agents

A coding-agent session is something you drive. You see every tool call and
approve it. A **scheduled agent** is not. It runs on a cron, headless, and keeps
running long after you set it up.

"Set it and forget it" assumes the agent's behaviour next week is the agent's
behaviour today. It rarely is. The routine's allowed tools get widened during a
debug session and never narrowed back. Its schedule changes. A new hook drops
into `settings.json` and now a command runs on every session start. None of it
announces itself.

This plugin fingerprints the things that run **without you watching** and warns
you the moment any of them drifts from a baseline you approved:

- **routines** — declared scheduled-agent specs: schedule, allowed tools, MCP
servers, prompt, model.
- **hooks** — the commands in `~/.claude/settings.json` that auto-run on events
(`SessionStart`, `PreToolUse`, …).

## Install

```
# from this directory, or point Claude Code at the marketplace.json at the repo root
/plugin install agentrust-scheduled-agents
```

The `SessionStart` hook is dependency-free (Python standard library only), so it
never blocks a session. On first run it records a baseline. After that it stays
quiet until something moves, then prints one line:

```
AgenTrust WARNING: 2 change(s) to what runs without you watching since baseline:
added routine tool babysit-prs: Bash(curl:*); changed routine schedule babysit-prs: */30 * * * * -> * * * * *.
Run /schedule-manifest verify for detail, or /schedule-manifest approve to accept.
```

Then:

- `/schedule-manifest verify` — show exactly what changed, in plain English.
- `/schedule-manifest approve` — accept the current surface as the new baseline.
- `/schedule-manifest show` — display the surface without touching the baseline.
- `/schedule-trace` — write a signed, third-party-verifiable TRACE record.

## Declaring a routine

Claude Code does not expose its cloud routines on disk, so you **declare** each
scheduled agent's approved shape as a spec file. Drop one JSON file per routine
into `~/.claude/agentrust/routines/` (or set `AGENTRUST_ROUTINES_DIR`). A copy of
[`routines/babysit-prs.example.json`](routines/babysit-prs.example.json) to start
from:

```json
{
"name": "babysit-prs",
"schedule": "*/30 * * * *",
"prompt": "Check my open PRs and fix failing CI. Do not merge.",
"allowed_tools": ["Bash(gh:*)", "Read", "Grep", "Edit"],
"mcp_servers": ["github"],
"model": "claude-opus-4-8"
}
```

`prompt_file` (a path, absolute or relative to the routines dir) may be used
instead of an inline `prompt`. Commit these specs to version control: the
approved file is the source of truth, and drift is any later change to it.

## What it records, and what it does not

It records **names and fingerprints only** — routine, tool, MCP, and hook-command
names, and SHA-256 hashes of prompts and settings. It never stores secrets, never
reads your credentials file, and never records a hook command's output.

## Honest scope

- This baselines the **declared** routine specs and the **on-disk** hooks, and
detects drift in those declarations. It does not introspect a live cloud
routine's runtime behaviour — no software running on a normal dev box can prove
that.
- On a normal dev box this is **software integrity, Level 0**, never presented as
hardware-attested. `/schedule-trace` records `runtime.platform: software-only`
and `slsa_level: 0` accordingly.
- v1 reads the **global** `~/.claude/settings.json` hooks block. Project-scoped
hooks are on the roadmap.

## Verifying a TRACE record elsewhere

`trace.json` is signed with a persistent Ed25519 key; its public half is written
to `verification_key.json`. Anyone can verify it without trusting your machine:

```python
import json, agentrust_trace
rec = json.load(open("trace.json"))
vk = json.load(open("verification_key.json"))
agentrust_trace.verify_record(rec, vk["jwk"]) # raises if invalid
```

or against the public conformance suite:

```
trace-tests verify --record trace.json --level 0
```

## Tests

```
python -m pytest tests -q
```

The drift-detection tests use the standard library alone. The signing tests skip
cleanly when `agentrust-trace` is not installed.

## License

Apache-2.0.
43 changes: 43 additions & 0 deletions scheduled-agents/commands/schedule-manifest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
description: Check, approve, or show the integrity baseline of your Claude Code scheduled agents
argument-hint: "[verify | approve | show]"
---

You are running the AgenTrust scheduled-agent integrity command. It answers one
question: are the things that run WITHOUT the user watching -- their scheduled
routines and the hooks that auto-run on events -- the ones they approved, with
nothing added and nothing subtracted since their baseline?

The engine is at `${CLAUDE_PLUGIN_ROOT}/engine/capture.py`. It fingerprints:

- routine specs in `~/.claude/agentrust/routines/*.json` (override with
`AGENTRUST_ROUTINES_DIR`): each routine's schedule, allowed tools, MCP servers,
prompt, and model.
- the `hooks` block in `~/.claude/settings.json`: the commands that auto-run on
SessionStart, PreToolUse, and other events.

It diffs the current surface against the approved baseline at
`~/.claude/agentrust/scheduled/baseline.json`. Everything is read from disk, so
no live session context is needed.

Dispatch on `$ARGUMENTS`:

- `verify` (default): run
`python "${CLAUDE_PLUGIN_ROOT}/engine/capture.py" verify`.
Verify always re-reads the surface fresh, so it reflects any routine edited or
hook widened since session start. Show the result and explain each change in
plain language, then ask whether to approve it.
- `approve`: run
`python "${CLAUDE_PLUGIN_ROOT}/engine/capture.py" approve`. Use this when the
user confirms the changes are intentional. Add `--sign --out .` to also write a
signed TRACE record (needs `pip install -r "${CLAUDE_PLUGIN_ROOT}/requirements.txt"`).
- `show`: run
`python "${CLAUDE_PLUGIN_ROOT}/engine/capture.py" snapshot` to display the
current surface without touching the baseline.

Report the result in plain English. Name what changed (a routine added, a tool
widened, a schedule moved, a new auto-run hook) and what the user should do about
each. Be honest about scope: this baselines the DECLARED routine specs and the
on-disk hooks, and detects drift in those declarations. It does not introspect a
live cloud routine's runtime behaviour, and on a normal dev box it is
software-only (Level 0) integrity, not hardware attestation.
34 changes: 34 additions & 0 deletions scheduled-agents/commands/schedule-trace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
description: Generate a signed TRACE record of your Claude Code scheduled-agent surface
argument-hint: ""
---

You are running the AgenTrust scheduled-agent report command. Generate a signed
record of what currently runs without the user watching, and explain it in plain
English. Engine: `${CLAUDE_PLUGIN_ROOT}/engine/capture.py`.

Steps:

1. Ensure the signing package is installed (once):
`pip install -r "${CLAUDE_PLUGIN_ROOT}/requirements.txt"`.
2. Run
`python "${CLAUDE_PLUGIN_ROOT}/engine/capture.py" report --out .`
This writes `trace.json` (a TRACE Trust Record signed with the persistent key
at `~/.claude/agentrust/scheduled/signing_key.json`) and
`verification_key.json` (the public key a third party uses to verify it). The
private half never leaves the machine.
3. Optionally confirm the record passes the public suite:
`trace-tests verify --record trace.json --level 0` (or
`python -m trace_tests.cli verify --record trace.json --level 0`).

Then explain what the user cares about:

- what runs without them watching: their routines (schedule, tools, MCP, prompt)
and the auto-run hooks, each fingerprinted.
- whether any of it changed since their approved baseline.
- that the record is shareable: `trace.json` verifies on any machine with
`verification_key.json` and passes the public conformance suite at Level 0.

Be honest about scope. This is software-only integrity (Level 0), not hardware
attestation, and it fingerprints the declared routine specs and on-disk hooks,
not a live cloud routine's runtime behaviour.
Loading
Loading