Execution Log: GitHub events trigger a harness session programmatically
Append-only log of progress. Issue #15 asks for the detailed design and the task breakdown; implementation follows once the spec is approved.
Phase transitions
| Phase | Entered | Reviewed/approved by | Notes |
|---|---|---|---|
| requirements-definition | 2026-07-02 | @MadaraUchiha-314 (PR #16) | Distilled from issue #15 |
| design | 2026-07-02 | @MadaraUchiha-314 (PR #16) | MCP vs webhook decision → decision-016 |
| tasks-breakdown | 2026-07-02 | @MadaraUchiha-314 (PR #16) | 10-task DAG |
| implementation | 2026-07-02 | — | approved via "Let's implement it now." on PR #16 |
| needs-review | 2026-07-02 | all 10 tasks done; PR #16 updated | |
| complete |
Progress entries
2026-07-02 — Spec drafted (requirements → design → tasks)
- Phase: tasks-breakdown
- Did: Researched the two candidate approaches. Confirmed the official
github/github-mcp-serverhas no event-subscription capability (MCP transports are client-initiated; Claude.ai/code's PR-watching is Anthropic-hosted infrastructure) — recorded asdecision-016. Confirmed the official programmatic surfaces:claude -p --resume <session-id> --output-format json(session id in the JSON output; resume scoped to the project directory) andcursor-agent -p --resume <chat-id> --output-format json(Cursor's official SDK is TypeScript-only — answers the issue's TODO). Draftedrequirements.md(R1–R5 + NFRs),design.md(registry / router / dispatcher / adapters on top of the existinggh-webhookreceiver) and the 10-task DAG intasks.md. - Checkpoint/tests:
make lint(markdownlint) on the new docs. - Next: Human review of the three phases; then execute the DAG.
- Blockers: Phase approvals (
workflow.requireHumanReviewPerPhase: true); open questions raised on the ticket (label-gating forspawnOnUnmatched).
2026-07-02 — Design review feedback addressed (MCP notifications, SDK adapters)
- Phase: tasks-breakdown
- Did: Addressed @MadaraUchiha-314's PR #16 review: (1) sharpened decision-016 — MCP does define in-session notifications (
resources/subscribe,listChanged), but they only reach a connected client, the GitHub MCP server declares no event surface, and an event-pushing MCP server still needs a webhook receiver; (2) promoted the Claude Python-SDK adapter from "future work" to an explicit opt-in extra (the-loop[claude-sdk], new optional task 10) — verifiedclaude-agent-sdkcarries runtime deps (anyio,mcp,sniffio) and drives theclaudeCLI over stdio, so the stdlib CLI adapter stays default; Cursor's TypeScript SDK would need a Node sidecar, so its adapter stays CLI-only. - Checkpoint/tests:
make checkgreen. - Next: Phase approvals.
- Blockers: none new.
2026-07-02 — Owner decision: CLI-only triggering for both harnesses
- Phase: tasks-breakdown
- Did: Applied @MadaraUchiha-314's decision on PR #16 ("let's use cli to trigger the harnesses not the sdks, for both cursor and claude"): removed the optional Claude Python-SDK adapter (former task 10) from the design and DAG; recorded the CLI-only decision in
design.mdtrade-offs anddecision-016. TheHarnessAdaptercontract still permits SDK implementations later (R4.5). - Checkpoint/tests:
make checkgreen. - Next: Phase approvals.
- Blockers: none.
2026-07-02 — Implementation: tasks 1–10 executed
- Phase: implementation → needs-review
- Did: Executed the DAG in order 1 → {2,4,5,6,7} → 3 → 8 → 9 → 10. Red→green evidence per task:
- Task 1:
validate_config.pyINVALID ('routing' was unexpected) → schema extended → VALID. - Tasks 2/4/5/6/7:
pytest cli/tests/test_routing.pycollection error (No module named 'the_loop.harness') → modules implemented → 32 passed. - Task 3:
pytest -k sessions_command5 failed (command missing) → 5 passed. - Task 8: integration tests 3 failed (
--routeunknown; on_event lacked the delivery id) → wired → 57 passed total; scenarios queryable viathe-loop scenarios(4 rows, Requirement-linked). - Tasks 9/10: docs (CLI README, automation.md, architecture.md), records (decision-016 accepted, roadmap item shipped), markdownlint 0 errors.
- Task 1:
- Checkpoint/tests:
make checkgreen (ruff · pyright · validate · 57 pytest · markdownlint). - Next: Human review of PR #16 (autonomy tier 3: human-approves-pr).
- Blockers: none.
2026-07-02 — CI red: ruff-format drift; gate parity fixed
- Phase: needs-review
- Did: CI (pre-commit) failed on
ruff formatfor the new files —make checkdid not include a format check, so local was green while CI was red (exactly the tooling drift the-loop forbids). Applied the formatter, and added aformat-checktarget tomake checkso the gap cannot recur. - Checkpoint/tests:
uv run pre-commit run --all-filesall hooks Passed;make check(now incl. format-check) green. - Next: CI green on the re-push; human review.
- Blockers: none.
2026-07-02 — Expanded integration scenarios (reviewer request, PR #16)
- Phase: needs-review
- Did: @MadaraUchiha-314 asked for integration tests that prove the harness is actually triggered, covering specific lifecycle scenarios. Refactored the integration suite around a
ServerFactory(live receiver + stub harness with configurable delay/exit + timing capture) and grew it from 4 to 10 end-to-end scenarios, one per question: idle-resume, unmatched-drop, unmatched-spawn, busy-session queueing (asserts the 2nd run starts after the 1st ends), parallel across different items (asserts overlap), duplicate-once, harness-error isolation + redelivery-retry, bad-HMAC→401, disabled-event-type ignored. All assert on the stub CLI's real argv/cwd/timing. Ran the timing-sensitive ones 3× for flake safety. - Checkpoint/tests:
make checkgreen (63 pytest, incl. 10 Gherkin integration scenarios queryable viathe-loop scenarios). - Next: Review.
- Blockers: none.
2026-07-02 — Auto-close session on PR merge/close (reviewer request, PR #16)
- Phase: needs-review
- Did: @MadaraUchiha-314 confirmed the receiver should auto-close a session when its PR closes. Added dispatcher handling: a
pull_requestclosedevent closes the matched session(s) in the registry instead of resuming, and never spawns on a close. Updated the prompt templates (self-close guidance → "the receiver auto-closes"), design (Dispatcher §4 + Open→Resolved), CLI README, and automation.md. New tests: 3 unit (auto_closes_on_pr_close,pr_close_never_spawns, non-close PR still resumes) + 1 integration scenario (A session auto-closes when its PR is merged/closed). - Checkpoint/tests:
make checkgreen (67 pytest). - Next: Review.
- Blockers: none.
2026-07-02 — Label-gated auto-execution (reviewer request, PR #16)
- Phase: needs-review
- Did: @MadaraUchiha-314 specified a GitHub auto-execution workflow. Added new requirement R6 and implemented it:
spawnOnUnmatched: labeledmode + configurableautoExecuteLabel(defaultthe-loop: auto-execute). The router now reads label presence from the payload (event_carries_label:labeledaction'slabel.nameor the item's currentlabels) and setsRoutedEvent.labeled; the dispatcher spawns only for labelled items underlabeledmode, using a dedicated spawn prompt template (webhook-autoexecute-prompt.md) that kicks off/the-loop:work-on. Addedissuesto the event list. Config schema/template/repo config updated (repo default is nowlabeled). Two design decisions I made without a reply because the AskUserQuestion tool kept failing (connector flapping): (1) extend the enum withlabeledrather than replacenever/always(backward compatible); (2) a labelled spawn runs the fullwork-onloop — both stated on the PR for veto. - Checkpoint/tests:
make checkgreen (76 pytest; 13 integration scenarios). New tests: label detection, router flag, labeled-mode spawn-only-for-labelled, spawn prompt kicks off work-on,alwaysstill ignores the label, + 2 integration scenarios (label spawns; unlabelled new issue ignored). - Next: Meta — create the
the-loop: auto-executelabel + apply to issue #15 (needs GitHub MCP auth); reply on PR. Then review. - Blockers: GitHub MCP re-auth for the label meta-task.
Review cycles
| Cycle | Type (self/critic) | Reviewer | Outcome | Link |
|---|---|---|---|---|
| 1 | self | harness | Fixed: EARS phrasing, DAG edges, untrusted-payload handling made explicit | — |
| 2 | human | @MadaraUchiha-314 | Fixed: MCP-notifications rationale sharpened; optional Claude SDK adapter added | PR #16 comment |
| 3 | human | @MadaraUchiha-314 | Decision applied: CLI-only triggering for both harnesses; SDK adapter removed | PR #16 comment |
| 4 | self | harness | Fixed: router and dispatcher now share one Deduper (router's early duplicate check was inert); design §3 protocol snippet aligned with implemented signatures | — |
Final validation evidence
make checkgreen: ruff · pyright ·validate_config.py(schema + both configs) · 57 pytest (16 pre-existing + 41 new) · markdownlint (0 errors) — the same commands CI runs.- Acceptance mapping: R2 → registry +
sessionscommand tests; R3 → router/dispatcher tests + the three Gherkin integration scenarios (the-loop scenarioslists them withRequirement:links); R4 → adapter tests against stubclaude/cursor-agentbinaries (argv + cwd asserted); R5 → same-session FIFO / cross-session parallelism dispatcher tests; R1 →decision-016(accepted).