Loop template
Research Watch Loop
Monitor trusted sources and turn new, high-signal research changes into cited findings reports and optional follow-up tasks.
Human guide
Raw README.mdResearch Watch Loop
The research-watch loop monitors trusted sources on a schedule, writes a cited findings report, records duplicate-suppression state, and optionally routes high-signal findings into a pull request or kanban task.
This directory is a draft starter template. "Draft" is registry/site operational metadata for the template directory, not a hidden loop.yaml field; the manifest itself uses only the fields defined by spec/loop-spec-v0.1.md. The template is not running unattended just because these files exist or have been copied; an installed loop starts only after an operator customizes sources, paths, schedule, credentials, and enables an approved backend.
Files
loop.yaml— agent-readable manifest for the template.AGENT-INSTALL.md— exact install commands for cron, GitHub Actions, and agent-kanban backends.scripts/research_watch.py— concrete standard-library runner used by all backends.examples/sources.json— editable source list for a real run.examples/dry-run-sources.json— local-only source list used by verification.examples/github-actions/research-watch.yml— ready-to-copy workflow.verification/dry-read-ambiguity-checklist.md— independent dry-read checklist for this revision.
The seven human questions
1. What loop do I need?
Use this loop when a project needs recurring awareness of research, engineering posts, repositories, or source files, and the desired output is a dated findings report plus optional follow-up work. It matches the watchdog / monitor pattern in docs/research/loop-landscape.md §2 and the research-watch template recommendation in §6.1.
2. What can it safely automate?
The manifest permits reading web/repo/file sources, writing a report, writing a state file, creating a proposal branch, and creating a follow-up task. It forbids public publishing, spending money, deleting user data, and mutating source systems. These claims map to permissions.allowed_actions and permissions.forbidden_actions in loop.yaml.
3. What do I need to connect?
Minimum setup needs only this repository, Python 3, a JSON source list, an output directory, and a state path. GitHub Actions PR mode also needs the built-in GITHUB_TOKEN permissions declared in the workflow. Agent-kanban mode needs a configured task board or Hermes kanban installation. The default manifest does not require a web-search API key and does not include a web_search source.
4. What can go wrong?
Fetches can fail, sources can become stale, the same item can be reported twice if state is lost, and an agent can over-interpret weak evidence. The runner records fetch errors in the report, the state path is declared in state.paths, duplicate suppression is a verification requirement, and public/product-direction changes are human-gated.
5. How do I know it worked?
A successful run prints RESEARCH_WATCH_REPORT=..., RESEARCH_WATCH_STATE=..., NEW_ITEMS=..., and FETCH_ERRORS=.... The report must contain source URLs or repo-relative file paths for every item, and the state file must include the report path and seen keys. The exact verification commands are in loop.yaml under verification.commands and in AGENT-INSTALL.md.
After copying the template into a target repository, run the concrete verification block in AGENT-INSTALL.md before enabling cron, GitHub Actions, or agent-kanban. The local dry-run proves the copied starter files execute; it does not approve live scheduling, public publishing, product-direction changes, or credential use.
6. How do I stop or roll it back?
For cron, remove the research_watch.py line from the user's crontab. For GitHub Actions, disable or delete .github/workflows/research-watch.yml. For agent-kanban, pause or remove the recurring task. Rollback is intentionally narrow: leave the previous state file unchanged when report generation fails; if a bad report PR is opened, close the PR or revert that report commit. This maps to failure_policy.rollback.
7. What should I improve after the first run?
Review the source list, prune noisy sources, add stronger sources, adjust cadence, and calibrate what qualifies as a follow-up task. Record maintenance evidence in the audit log path declared by maintenance.audit_log; the template's freshness cadence is weekly.
Backend behavior
All supported backends run the same helper and the same manifest validation command. Backend differences are installation and delivery only:
cronwrites reports and state on the machine where cron runs.github_actionswrites reports/state on a branch and opens a pull request usingpeter-evans/create-pull-request.agent_kanbancreates a recurring agent task whose prompt runs the helper, reviews output, and creates follow-up cards only for high-signal findings.
Optional web-search sources
The default template avoids web-search credentials so the installed loop works with public RSS/URL/repo/file sources. If an operator later enables a web-search provider, they must update all three places together:
- add a
web_searchsource toloop.yamland to the runtime source JSON; - add the provider's env var name to
inputs.environment_variablesand a matching credential scope topermissions.credential_scopes; - persist the secret in the backend's supported secret store, such as a cron env file or GitHub Actions secret.
If no credential exists, do not add the web_search source, env var, or credential scope.
The job description (loop.yaml)
View raw loop.yamlspec_version: "0.1"
id: research-watch
name: Research Watch Loop
purpose: Monitor trusted sources and turn new, high-signal research changes into cited findings reports and optional follow-up tasks.
audience: [human, agent, operator]
trigger:
type: schedule
default: weekly
schedule: "0 9 * * 1"
inputs:
sources:
- type: rss
name: Practitioner and lab engineering feeds
url: templates/research-watch/examples/sources.json
- type: url
name: Stable source URLs
url: templates/research-watch/examples/sources.json
- type: github_repo
name: Agent framework repositories
url: templates/research-watch/examples/sources.json
files:
- templates/research-watch/examples/sources.json
- templates/research-watch/scripts/research_watch.py
capabilities:
- polling
- source_summarization
- dedupe
- cited_reporting
- task_creation
permissions:
allowed_actions:
- read_web
- read_repo
- write_report
- write_state
- create_proposal_branch
- create_task
forbidden_actions:
- publish_publicly_without_approval
- spend_money
- delete_user_data
- mutate_source_systems
credential_scopes:
- repo:contents:write
- pull_request:write
- kanban:create
state:
paths:
- .loopmaster/state/research-watch.json
retention: 90 days
outputs:
artifacts:
- docs/research/YYYY-MM-DD-research-watch.md
notifications:
- run_summary
tasks:
- kanban_card_for_high_signal_finding
verification:
required:
- every reported item includes a source URL or repo-relative source path
- report records whether it acted autonomously or needs approval
- state file prevents duplicate reporting on repeated runs
- public publishing and product direction changes remain human-gated
commands:
- name: validate loop manifest
run: uv run --with check-jsonschema --with pyyaml check-jsonschema --schemafile spec/loop.schema.json templates/research-watch/loop.yaml
expected: exits 0 and prints ok -- validation done
- name: dry-run runner against local example source
run: python3 templates/research-watch/scripts/research_watch.py --sources templates/research-watch/examples/dry-run-sources.json --state /tmp/loopmaster-research-watch-state.json --output-dir /tmp/loopmaster-research-watch --max-items 5
expected: exits 0 and prints RESEARCH_WATCH_REPORT and RESEARCH_WATCH_STATE paths
human_gates:
required_for:
- public publishing
- product direction changes
- credential changes
- merging proposed resource entries
approver: maintainer
failure_policy:
retry: 2
escalate_after: repeated_fetch_or_validation_failure
rollback: leave the previous state file unchanged when report generation fails; delete only the failed run artifact after recording the error
maintenance:
freshness_cadence: weekly
owner: Loopmaster maintainers
audit_log: loops/log/
backends:
cron:
schedule: "0 9 * * 1"
install_notes:
- Runs the checked-in Python helper from the target repository root.
- Uses a persistent env file when optional credentials are enabled; no one-time shell exports are assumed to survive cron.
github_actions:
workflow: .github/workflows/research-watch.yml
install_notes:
- Workflow runs weekly or manually, writes a report, updates state, and opens a pull request with those changes.
agent_kanban:
task_template: Create a weekly research-watch task that runs the helper, reviews the report, and creates follow-up cards only for high-signal findings.
install_notes:
- Kanban installation assigns a recurring agent task; the agent still runs the same helper and verification commands.
Install guide (for your agent)
Raw for agentsAgent install guide — Research Watch Loop
Run commands from the repository root unless a step says otherwise. Replace paths only when your target repo intentionally uses different report/state locations.
This directory is a starter template, not an installed unattended loop. Copy it into the target repository, customize the source list, schedule, report/state paths, and any credential storage, then get human approval before enabling a scheduler, publishing findings, changing product direction, or using new credentials.
If you copied the template into another repository at templates/research-watch/, verify the copied files before installing a backend:
test -f templates/research-watch/loop.yaml
test -f templates/research-watch/AGENT-INSTALL.md
python3 templates/research-watch/scripts/research_watch.py --help >/tmp/loopmaster-research-watch-help.txt
uv run --with check-jsonschema --with pyyaml check-jsonschema \
--schemafile spec/loop.schema.json \
templates/research-watch/loop.yaml
rm -rf /tmp/loopmaster-research-watch /tmp/loopmaster-research-watch-state.json
python3 templates/research-watch/scripts/research_watch.py \
--sources templates/research-watch/examples/dry-run-sources.json \
--state /tmp/loopmaster-research-watch-state.json \
--output-dir /tmp/loopmaster-research-watch \
--max-items 5Expected verification: the schema command prints ok -- validation done; the runner prints RESEARCH_WATCH_REPORT=..., RESEARCH_WATCH_STATE=..., NEW_ITEMS=1, and FETCH_ERRORS=0. If you copied the template under a different path, update every command and loop.yaml reference deliberately before running the checks.
0. Preflight
python3 --version
python3 templates/research-watch/scripts/research_watch.py --help
uv run --with check-jsonschema --with pyyaml check-jsonschema \
--schemafile spec/loop.schema.json \
templates/research-watch/loop.yamlExpected output:
Python 3.x.x
usage: research_watch.py ...
ok -- validation doneFailure branches:
python3: command not found— install Python 3 or use a backend image that includes it.No such file or directory— confirm you are at repo root and thattemplates/research-watch/exists.- schema validation failure — fix
loop.yamlbefore installing any backend.
1. Verify the concrete runner locally
rm -rf /tmp/loopmaster-research-watch /tmp/loopmaster-research-watch-state.json
python3 templates/research-watch/scripts/research_watch.py \
--sources templates/research-watch/examples/dry-run-sources.json \
--state /tmp/loopmaster-research-watch-state.json \
--output-dir /tmp/loopmaster-research-watch \
--max-items 5Expected output shape:
RESEARCH_WATCH_REPORT=/tmp/loopmaster-research-watch/YYYY-MM-DD-research-watch.md
RESEARCH_WATCH_STATE=/tmp/loopmaster-research-watch-state.json
NEW_ITEMS=1
FETCH_ERRORS=0Then verify duplicate suppression:
python3 templates/research-watch/scripts/research_watch.py \
--sources templates/research-watch/examples/dry-run-sources.json \
--state /tmp/loopmaster-research-watch-state.json \
--output-dir /tmp/loopmaster-research-watch \
--max-items 5Expected output: NEW_ITEMS=0 and FETCH_ERRORS=0.
Failure branches:
FETCH_ERRORSis non-zero on the dry run — the local file source is unreadable; fix the path inexamples/dry-run-sources.json.- report is missing source evidence — inspect the generated Markdown and fix the source config before scheduling.
2. Configure sources
Edit a project-local copy of templates/research-watch/examples/sources.json. Keep the top-level shape:
{
"sources": [
{"type": "rss", "name": "Example feed", "url": "https://example.com/feed.xml"},
{"type": "url", "name": "Important page", "url": "https://example.com/important"},
{"type": "github_repo", "name": "Example repo", "url": "https://github.com/example/repo"},
{"type": "file", "name": "Local notes", "path": "docs/research/loop-landscape.md"}
]
}Supported by the checked-in runner: file, url, rss, and github_repo.
The dry-run source file proves the starter template is runnable; it is not the live installed loop. A live loop is installed only after this source file is replaced with project-specific targets, report/state paths are chosen, credentials are persisted in the backend secret store if needed, and the chosen backend is enabled with maintainer approval.
No web-search credential exists by default. If no credential exists, do not add web_search to sources.json, do not add a web_search source to loop.yaml, and do not add a web-search credential scope or env var. This keeps README.md, loop.yaml, and runtime behavior consistent.
If you later add a real web-search provider, persist its secret in the backend secret store and update the manifest and runtime source file in the same PR. A one-time export WEB_SEARCH_API_KEY=... is not a valid cron install because cron does not inherit that interactive shell.
3. Backend A — cron
Cron runs on one machine and writes reports/state into that checkout. It does not open a PR by itself.
Create a persistent environment file, even if it currently contains no secrets:
mkdir -p .loopmaster/state .loopmaster/env docs/research
cat > .loopmaster/env/research-watch.env <<'EOF'
# Optional secrets go here as KEY=value lines.
# Do not commit this file.
RESEARCH_WATCH_SOURCES=templates/research-watch/examples/sources.json
RESEARCH_WATCH_STATE=.loopmaster/state/research-watch.json
RESEARCH_WATCH_OUTPUT_DIR=docs/research
EOF
chmod 600 .loopmaster/env/research-watch.env
printf '\n.loopmaster/env/*.env\n' >> .git/info/excludeInstall the cron entry:
REPO_ROOT=$(pwd)
CRON_LINE="0 9 * * 1 cd $REPO_ROOT && set -a && . ./.loopmaster/env/research-watch.env && set +a && /usr/bin/env python3 templates/research-watch/scripts/research_watch.py --sources \"$RESEARCH_WATCH_SOURCES\" --state \"$RESEARCH_WATCH_STATE\" --output-dir \"$RESEARCH_WATCH_OUTPUT_DIR\" >> .loopmaster/state/research-watch.cron.log 2>&1"
( crontab -l 2>/dev/null | grep -v 'templates/research-watch/scripts/research_watch.py' ; printf '%s\n' "$CRON_LINE" ) | crontab -
crontab -l | grep 'research_watch.py'Expected output: one crontab line containing templates/research-watch/scripts/research_watch.py.
Test the exact command outside cron:
set -a && . ./.loopmaster/env/research-watch.env && set +a
python3 templates/research-watch/scripts/research_watch.py \
--sources "$RESEARCH_WATCH_SOURCES" \
--state "$RESEARCH_WATCH_STATE" \
--output-dir "$RESEARCH_WATCH_OUTPUT_DIR"Expected output: RESEARCH_WATCH_REPORT=docs/research/..., RESEARCH_WATCH_STATE=.loopmaster/state/research-watch.json, and counts.
Failure branches:
crontab: command not found— this backend is unavailable; use GitHub Actions or agent-kanban.- cron log shows missing env vars — check
.loopmaster/env/research-watch.envpermissions and theset -a && . ...segment. - secrets are needed — add
KEY=valueto.loopmaster/env/research-watch.envonly; never commit it and never rely on a one-time interactiveexport. FETCH_ERRORSis non-zero — inspect.loopmaster/state/research-watch.cron.logand the generated report; fix sources or network access before treating the run as verified.
Stop cron:
crontab -l | grep -v 'templates/research-watch/scripts/research_watch.py' | crontab -4. Backend B — GitHub Actions
GitHub Actions runs weekly or manually, writes a report/state update, and opens a PR. It uses repository permissions, not local cron secrets.
Install the workflow:
mkdir -p .github/workflows .loopmaster/state docs/research
cp templates/research-watch/examples/github-actions/research-watch.yml .github/workflows/research-watch.yml
git add .github/workflows/research-watch.yml templates/research-watch/examples/sources.json
git diff --cached -- .github/workflows/research-watch.ymlExpected output: a workflow containing:
permissions:
contents: write
pull-requests: writeCommit and push the workflow in the normal PR flow. After merge, run it manually:
gh workflow run research-watch.yml
sleep 10
gh run list --workflow research-watch.yml --limit 1Expected output shape:
STATUS TITLE WORKFLOW BRANCH EVENT ID ELAPSED AGEWhen the run succeeds, expected result is a new PR titled docs(research): add research watch report if the runner changed docs/research/*.md or .loopmaster/state/research-watch.json. If there are no changes because state already contains all items, peter-evans/create-pull-request completes without opening a duplicate PR.
Failure branches:
gh: command not foundor unauthenticated — use the GitHub web UI to run the workflow, or authenticategh.- workflow fails at checkout or permission step — confirm repo Actions permissions allow
contents: writeandpull-requests: write. - workflow fails in
Run research watch— inspect the run log; fixexamples/sources.jsonor network assumptions. - web-search source added without secret — remove the
web_searchsource and matching manifest credential fields, or add the provider secret under GitHub repository Settings → Secrets and variables → Actions and reference it in the workflowenv:block.
Disable GitHub Actions backend:
git rm .github/workflows/research-watch.yml
git commit -m "chore: disable research watch workflow"5. Backend C — agent-kanban
Agent-kanban assigns a recurring task to an agent. The task must still run the concrete helper and record evidence; it is not a prose-only reminder.
For Hermes kanban, create a recurring scheduler job or board task whose prompt is self-contained. Example prompt:
Run the Loopmaster research-watch loop from repo root. Commands:
1. uv run --with check-jsonschema --with pyyaml check-jsonschema --schemafile spec/loop.schema.json templates/research-watch/loop.yaml
2. python3 templates/research-watch/scripts/research_watch.py --sources templates/research-watch/examples/sources.json --state .loopmaster/state/research-watch.json --output-dir docs/research
Then read the generated report path printed as RESEARCH_WATCH_REPORT. If NEW_ITEMS is greater than 0, summarize high-signal findings and create follow-up kanban cards only for evidence-backed actionable items. Do not publish public claims or change product direction without human approval. Complete with the report path, state path, counts, and any cards created.Using Hermes native cron job scheduling from an agent session:
cronjob(action="create", name="Loopmaster research watch", schedule="0 9 * * 1", workdir="/absolute/path/to/repo", prompt="<the self-contained prompt above>")Expected result: the scheduler returns a job id. On each run, completion evidence must include RESEARCH_WATCH_REPORT, RESEARCH_WATCH_STATE, NEW_ITEMS, and FETCH_ERRORS.
Failure branches:
- no kanban or scheduler backend exists — use cron or GitHub Actions instead.
- agent creates tasks without running the helper — reject the run; the backend is misinstalled because this template's verification requires the concrete helper output.
- agent wants to publish findings publicly or change positioning — block for human approval as declared in
human_gates.required_for.
6. Final install verification checklist
Before calling an install complete, record:
uv run --with check-jsonschema --with pyyaml check-jsonschema \
--schemafile spec/loop.schema.json \
templates/research-watch/loop.yaml
python3 templates/research-watch/scripts/research_watch.py \
--sources templates/research-watch/examples/dry-run-sources.json \
--state /tmp/loopmaster-research-watch-state.json \
--output-dir /tmp/loopmaster-research-watch \
--max-items 5Expected success:
ok -- validation done
RESEARCH_WATCH_REPORT=/tmp/loopmaster-research-watch/YYYY-MM-DD-research-watch.md
RESEARCH_WATCH_STATE=/tmp/loopmaster-research-watch-state.json
NEW_ITEMS=0 or 1
FETCH_ERRORS=0If any expected line is missing, the install is not verified.
How we know it works
- Status
- tested
- Date
- 2026-07-07
- Stale after
- 2026-08-06
dated checks passed
templates/research-watch/verification/dry-read-ambiguity-checklist.md
What it's allowed to do
6 allowed action(s), 4 forbidden action(s), 3 credential scope(s)
- Allowed actions
- read_web, read_repo, write_report, write_state, create_proposal_branch, create_task
- Credential scopes
- repo:contents:write, pull_request:write, kanban:create
- Forbidden actions
- publish_publicly_without_approval, spend_money, delete_user_data, mutate_source_systems