# Agent execution contract: Claude Code TTL heuristic + heartbeat

## Goal

Add a reversible TTL-estimate segment without losing existing statusline behavior, and teach the user to request a bounded, approximate 50-minute heartbeat for suitable long tasks.

## Non-negotiable boundaries

- Treat the TTL display as a heuristic, not observed cache state.
- Do not claim every Claude Max or Claude Code session has a one-hour TTL.
- Do not infer overage state from local files or usage percentages.
- Do not overwrite the whole `~/.claude/settings.json`.
- Do not replace or edit an existing statusline script when the mux can preserve it.
- Do not start a heartbeat unless a long-running task exists and monitoring is wanted.
- Do not leave a heartbeat running after completion or three no-progress checks.
- Do not claim `/loop 50m` fires exactly every 50 minutes or guarantees cache refresh before an assumed one-hour TTL.
- The mux re-executes the pre-install statusline command through `/bin/sh` to preserve its existing semantics. Treat that command as trusted local configuration; status JSON is passed only on stdin. If the existing command is not trusted, stop instead of preserving it.

## Procedure

1. Read <https://code.claude.com/docs/en/statusline> and confirm the current `statusLine` and `refreshInterval` contract.
2. Read <https://code.claude.com/docs/en/scheduled-tasks> and confirm `/loop` syntax, cron rounding, jitter, busy-turn delay, session scope, and seven-day expiry.
3. Inspect only required local state: Claude Code version; whether `~/.claude/settings.json` parses; whether `statusLine` is a command object; whether the target install directory exists. Never print the existing command body, secrets, hooks, or unrelated settings.
4. Download the three Python assets and `checksums.sha256` from this site. Verify SHA-256 before execution.
5. Run `python3 install_statusline.py --check`. If unsupported, stop; do not improvise a destructive replacement.
6. Summarize exact changes and obtain authorization if required by the host.
7. Run `python3 install_statusline.py --apply`.
8. Run `python3 install_statusline.py --verify`. It must verify the executable mux-config hash and mode `0600` for settings, mux config, receipt, and backups; modified executable config must fail closed.
9. Start or resume Claude Code. Confirm both the pre-existing output and `ttl~ HH:MM` are present.
10. Optional expiry test: launch from a shell with `CLAUDE_CACHE_TTL_SECONDS=60`, send a message, wait for timer refresh, and verify the red expiry block. Restore the environment afterwards.
11. Report backup and receipt paths without exposing contents.

## Rollback

From the download directory:

```bash
python3 install_statusline.py --uninstall
```

Confirm the previous statusline behavior is restored. The installer refuses rollback if a newer command replaced the managed command.

## Heartbeat command

Only while a suitable background task is running:

```text
/loop 50m Cache/heartbeat check-in. If a background task is running, do a quick non-blocking peek at its progress and report anything notable. Stop this loop once the task is done, or after 3 consecutive checks with no completion and no new progress. Otherwise reply "ok".
```

Keep a check counter in the session conversation. Cancel when either stop condition fires. This schedule is session-scoped.

After creating the loop:

1. Read Claude's confirmation rather than assuming the requested interval was accepted exactly.
2. List scheduled tasks and report the actual cron cadence and job ID.
3. State that recurring tasks running more often than hourly can receive deterministic jitter up to half the interval, and that a busy turn can delay execution further.
4. Count three observed heartbeats, not an assumed 150 minutes.
5. State that recurring tasks fire once more and delete themselves seven days after creation.

The heartbeat is a missed-notification fallback. It is not evidence of cache state and cannot guarantee a refresh before a one-hour TTL.

## Success criteria

- Exact pre-change settings backup exists.
- Unrelated settings remain semantically identical.
- The previous statusline command still runs through the mux, if one existed.
- `refreshInterval` is exactly 60 seconds.
- The TTL segment updates during idle time.
- The actual scheduled cadence and job ID are recorded, with rounding/jitter caveats.
- Rollback restores the previous `statusLine` object.
