Skip to main content

Lightweight, extensible CLI for the-loop — quality-of-life commands the the-loop plugin can use (e.g. a GitHub webhook receiver).

Project description

the-loop CLI

A lightweight, extensible command-line companion to the the-loop plugin, written in Python (stdlib-only core — zero runtime dependencies). Python is intentional: it leaves room to add self-learning / ML capabilities later (mostly exposed as Python SDKs).

Install

From PyPI (published as the-loopy-one — the base name the-loop was taken; the import package and CLI keep the natural the_loop/the-loop):

pip install the-loopy-one            # or: uv pip install the-loopy-one
pip install "the-loopy-one[config]"  # + PyYAML, for reading .the-loop/config.yaml defaults
the-loop --help

For local development the-loop uses uv (its declared Python package manager). From the repo root:

uv sync                     # installs the workspace (this CLI + dev tooling) from uv.lock
uv run the-loop --help      # run the CLI

Or install this package on its own with any PEP 517 installer:

uv pip install -e .            # or: pip install -e .
uv pip install -e ".[config]"  # PyYAML, for reading .the-loop/config.yaml defaults
uv pip install -e ".[dev]"     # pytest + commitizen

This exposes the primary CLI: the-loop. Releases are automatic: on merge to main, .github/workflows/release.yml runs cz bump to derive the next version from the Conventional Commits / PR titles since the last tag (feat → minor, fix → patch, BREAKING CHANGE → major), tags it, and publishes to PyPI via Trusted Publishing (OIDC — no stored token). Merges with no feat/fix/breaking change publish nothing. See docs/decisions/decision-019.md.

Commands

gh-webhook — GitHub webhook receiver

the-loop gh-webhook start [--host 127.0.0.1] [--port 8787] [--path /gh-webhook] \
                          [--pidfile .the-loop/gh-webhook.pid] \
                          [--secret-env THE_LOOP_GH_WEBHOOK_SECRET] \
                          [--route | --no-route]
the-loop gh-webhook stop  [--pidfile .the-loop/gh-webhook.pid]
  • Verifies the GitHub X-Hub-Signature-256 HMAC when the secret env var is set (export THE_LOOP_GH_WEBHOOK_SECRET=...). The secret is read from the environment, never a flag, so it doesn't leak into process listings.
  • GET /health returns 200 ok.
  • Defaults can come from .the-loop/config.yaml (webhooks.ghWebhook) when PyYAML is installed; flags always override.
  • --route (default from webhooks.ghWebhook.routing.enabled) routes each verified event to the registered harness session working that item: the router extracts the work item(s) from the payload (issue/PR number, PR head-branch issue-<n> convention, closing keywords, workflow_run/check_* PRs), deduplicates on X-GitHub-Delivery, and the dispatcher resumes the matched session via its official CLI (claude -p … --resume <session-id> / cursor-agent -p … --resume <chat-id>), one event at a time per session, in parallel across sessions. Unmatched events follow routing.spawnOnUnmatched (never drops; always spawns + registers a session). Design: docs/specs/issue-15/design.md, docs/decisions/decision-016.md.

sessions — link work items to harness sessions (webhook routing)

the-loop sessions register --work-item github:OWNER/REPO#N --harness claude \
    --harness-session-id "$CLAUDE_SESSION_ID" [--cwd .] [--force]
the-loop sessions list  [--status active|closed] [--format table|json]
the-loop sessions close --work-item github:OWNER/REPO#N
  • The registry lives in webhooks.ghWebhook.routing.registryDir (default .the-loop/sessions/, git-ignored) as one human-inspectable JSON file per session; writes are atomic, so concurrent sessions on the same machine are safe.
  • One work item ↔ one active session; --force replaces a stale registration.
  • Claude Code sessions register with $CLAUDE_SESSION_ID; Cursor sessions register with the chat id they were launched with (non-interactive cursor-agent ls is unreliable for id discovery, so the id is captured at registration time).
  • When a work item's PR is merged or closed, the receiver auto-closes the session (on the pull_request closed event) — no manual sessions close needed.

Label-gated auto-execution (spawnOnUnmatched: labeled): give an issue/PR the configurable routing.autoExecuteLabel (default the-loop: auto-execute) and the receiver spawns a session and starts /the-loop:work-on on it — then routes that item's later activity (comments, reviews, CI, its linked PR) to the same session, and auto-closes on PR merge. Label presence is read straight from the webhook payload (no extra API call). A new issue without the label is received and ignored.

scenarios — query the Gherkin scenarios integration tests cover

the-loop scenarios [--root .] [--glob PATTERN ...] [--format table|markdown|json]
  • Scans integration-test files for the Gherkin-syntax docstrings the-loop requires (Feature: / Scenario: / Given-When-Then, plus an optional Requirement: link to a requirements.md) and presents them as a table — so a coding-agent harness can answer "what scenarios are tested?" without running anything.
  • Language-agnostic: Python docstrings, JS/TS block comments and Go comments all work.
  • Globs come from --glob (repeatable), else testing.integrationTestGlobs in .the-loop/config.yaml (when PyYAML is installed), else built-in defaults covering common layouts.
  • --format markdown emits a GitHub-flavoured table (for PR briefings); --format json is machine-readable (includes each scenario's steps and file:line).

Adding a command (extensibility)

  1. Create the_loop/commands/<your_command>.py.
  2. Subclass Command, set name/help, implement add_arguments and run, and decorate the class with @register.
  3. Import the module in the_loop/commands/__init__.py.

The CLI discovers registered commands automatically.

Test

pytest        # from this directory

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

the_loopy_one-0.3.0.tar.gz (36.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

the_loopy_one-0.3.0-py3-none-any.whl (32.5 kB view details)

Uploaded Python 3

File details

Details for the file the_loopy_one-0.3.0.tar.gz.

File metadata

  • Download URL: the_loopy_one-0.3.0.tar.gz
  • Upload date:
  • Size: 36.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for the_loopy_one-0.3.0.tar.gz
Algorithm Hash digest
SHA256 4cb3c19b2612134c67ddb4e7c4f567da1022f2ddd1c16dff3cf7ef3325f62fe3
MD5 e6f710146768be10dbc9c81bc650a0d9
BLAKE2b-256 318d0d3c7d4add9bb334a0711ac87c8b6a546d5d43ac9ce8039c5bf00339f0f1

See more details on using hashes here.

Provenance

The following attestation bundles were made for the_loopy_one-0.3.0.tar.gz:

Publisher: release.yml on MadaraUchiha-314/the-loop

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file the_loopy_one-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: the_loopy_one-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 32.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for the_loopy_one-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0039513361840a5888461ee2f35efd4735c92e4357953e22cda2e545174fd327
MD5 b73f27cb6644fcb8f680afd4f5716694
BLAKE2b-256 2a5b7af18546751bc906a4ef7b85106b527d61d4513873afccdc757b9e6bd0d3

See more details on using hashes here.

Provenance

The following attestation bundles were made for the_loopy_one-0.3.0-py3-none-any.whl:

Publisher: release.yml on MadaraUchiha-314/the-loop

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page