loopcaptain 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- loopcaptain-0.3.1/.agent/AGENT_IMPROVEMENTS.md +11 -0
- loopcaptain-0.3.1/.agent/DEFERRED_VERIFICATION.md +13 -0
- loopcaptain-0.3.1/.agent/FINDINGS.md +17 -0
- loopcaptain-0.3.1/.agent/UPSTREAM_ISSUES.md +8 -0
- loopcaptain-0.3.1/.editorconfig +23 -0
- loopcaptain-0.3.1/.env.example +16 -0
- loopcaptain-0.3.1/.github/CODEOWNERS +2 -0
- loopcaptain-0.3.1/.github/ISSUE_TEMPLATE/bug.yml +26 -0
- loopcaptain-0.3.1/.github/ISSUE_TEMPLATE/config.yml +5 -0
- loopcaptain-0.3.1/.github/ISSUE_TEMPLATE/loop-not-showing.yml +23 -0
- loopcaptain-0.3.1/.github/ISSUE_TEMPLATE/protocol.yml +25 -0
- loopcaptain-0.3.1/.github/dependabot.yml +32 -0
- loopcaptain-0.3.1/.github/pull_request_template.md +19 -0
- loopcaptain-0.3.1/.github/workflows/ci.yml +69 -0
- loopcaptain-0.3.1/.github/workflows/docs.yml +57 -0
- loopcaptain-0.3.1/.github/workflows/links.yml +28 -0
- loopcaptain-0.3.1/.github/workflows/pr-description.yml +62 -0
- loopcaptain-0.3.1/.github/workflows/release.yml +108 -0
- loopcaptain-0.3.1/.github/workflows/scorecard.yml +35 -0
- loopcaptain-0.3.1/.github/workflows/security.yml +37 -0
- loopcaptain-0.3.1/.gitignore +23 -0
- loopcaptain-0.3.1/.pre-commit-config.yaml +130 -0
- loopcaptain-0.3.1/.python-version +1 -0
- loopcaptain-0.3.1/AGENTS.md +276 -0
- loopcaptain-0.3.1/CHANGELOG.md +103 -0
- loopcaptain-0.3.1/CITATION.cff +17 -0
- loopcaptain-0.3.1/CLAUDE.md +1 -0
- loopcaptain-0.3.1/CODE_OF_CONDUCT.md +10 -0
- loopcaptain-0.3.1/CONTRIBUTING.md +26 -0
- loopcaptain-0.3.1/GEMINI.md +1 -0
- loopcaptain-0.3.1/LICENSE +202 -0
- loopcaptain-0.3.1/Makefile +49 -0
- loopcaptain-0.3.1/NOTICE +11 -0
- loopcaptain-0.3.1/PKG-INFO +220 -0
- loopcaptain-0.3.1/README.md +185 -0
- loopcaptain-0.3.1/SECURITY.md +31 -0
- loopcaptain-0.3.1/docs/ARCHITECTURE.md +448 -0
- loopcaptain-0.3.1/docs/agents.md +200 -0
- loopcaptain-0.3.1/docs/assets/banner-dark.svg +19 -0
- loopcaptain-0.3.1/docs/assets/banner-light.svg +19 -0
- loopcaptain-0.3.1/docs/assets/hero-dark.svg +65 -0
- loopcaptain-0.3.1/docs/assets/hero-light.svg +65 -0
- loopcaptain-0.3.1/docs/assets/parts-dark.svg +49 -0
- loopcaptain-0.3.1/docs/assets/parts-light.svg +49 -0
- loopcaptain-0.3.1/docs/assets/request-dark.svg +62 -0
- loopcaptain-0.3.1/docs/assets/request-light.svg +62 -0
- loopcaptain-0.3.1/docs/assets/screenshot-connect-dark.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-connect.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-findings-dark.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-findings.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-loop-dark.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-loop.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-overview-dark.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-overview.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-rounds-dark.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-rounds.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-waiting-dark.webp +0 -0
- loopcaptain-0.3.1/docs/assets/screenshot-waiting.webp +0 -0
- loopcaptain-0.3.1/docs/assets/trust-dark.svg +29 -0
- loopcaptain-0.3.1/docs/assets/trust-light.svg +29 -0
- loopcaptain-0.3.1/docs/board.md +63 -0
- loopcaptain-0.3.1/docs/changelog.md +1 -0
- loopcaptain-0.3.1/docs/connect.md +1 -0
- loopcaptain-0.3.1/docs/contributing.md +1 -0
- loopcaptain-0.3.1/docs/get-started.md +67 -0
- loopcaptain-0.3.1/docs/index.md +45 -0
- loopcaptain-0.3.1/docs/installation.md +83 -0
- loopcaptain-0.3.1/docs/llms.txt +27 -0
- loopcaptain-0.3.1/docs/opentelemetry.md +46 -0
- loopcaptain-0.3.1/docs/protocol/index.md +1 -0
- loopcaptain-0.3.1/docs/reference/cli.md +142 -0
- loopcaptain-0.3.1/docs/reference/configuration.md +24 -0
- loopcaptain-0.3.1/docs/reference/mcp.md +85 -0
- loopcaptain-0.3.1/docs/security.md +1 -0
- loopcaptain-0.3.1/docs/setup.md +88 -0
- loopcaptain-0.3.1/pyproject.toml +103 -0
- loopcaptain-0.3.1/scripts/docs_pages.py +118 -0
- loopcaptain-0.3.1/scripts/forbidden_words.sh +21 -0
- loopcaptain-0.3.1/scripts/readme_assets.py +621 -0
- loopcaptain-0.3.1/scripts/release.py +109 -0
- loopcaptain-0.3.1/scripts/shots.py +125 -0
- loopcaptain-0.3.1/scripts/showcase.py +318 -0
- loopcaptain-0.3.1/src/loopcaptain/__init__.py +0 -0
- loopcaptain-0.3.1/src/loopcaptain/agents.py +162 -0
- loopcaptain-0.3.1/src/loopcaptain/board/AGENTS.md +39 -0
- loopcaptain-0.3.1/src/loopcaptain/board/__init__.py +0 -0
- loopcaptain-0.3.1/src/loopcaptain/board/app.py +430 -0
- loopcaptain-0.3.1/src/loopcaptain/board/discover.py +249 -0
- loopcaptain-0.3.1/src/loopcaptain/board/files.py +94 -0
- loopcaptain-0.3.1/src/loopcaptain/board/filters.py +48 -0
- loopcaptain-0.3.1/src/loopcaptain/board/graph.py +139 -0
- loopcaptain-0.3.1/src/loopcaptain/board/overview.py +59 -0
- loopcaptain-0.3.1/src/loopcaptain/board/static/board.js +41 -0
- loopcaptain-0.3.1/src/loopcaptain/board/static/fonts/OFL.txt +94 -0
- loopcaptain-0.3.1/src/loopcaptain/board/static/fonts/inter-latin-wght-normal.woff2 +0 -0
- loopcaptain-0.3.1/src/loopcaptain/board/static/fonts/inter-tight-latin-wght-normal.woff2 +0 -0
- loopcaptain-0.3.1/src/loopcaptain/board/static/mark.svg +5 -0
- loopcaptain-0.3.1/src/loopcaptain/board/static/style.css +425 -0
- loopcaptain-0.3.1/src/loopcaptain/board/steer.py +207 -0
- loopcaptain-0.3.1/src/loopcaptain/board/templates/base.html +27 -0
- loopcaptain-0.3.1/src/loopcaptain/board/templates/connect.html +35 -0
- loopcaptain-0.3.1/src/loopcaptain/board/templates/file.html +9 -0
- loopcaptain-0.3.1/src/loopcaptain/board/templates/loop.html +357 -0
- loopcaptain-0.3.1/src/loopcaptain/board/templates/overview.html +108 -0
- loopcaptain-0.3.1/src/loopcaptain/board/templates/unreadable.html +17 -0
- loopcaptain-0.3.1/src/loopcaptain/board/trend.py +185 -0
- loopcaptain-0.3.1/src/loopcaptain/cli.py +204 -0
- loopcaptain-0.3.1/src/loopcaptain/demo/__init__.py +59 -0
- loopcaptain-0.3.1/src/loopcaptain/demo/loop.py +311 -0
- loopcaptain-0.3.1/src/loopcaptain/mcp_server/AGENTS.md +23 -0
- loopcaptain-0.3.1/src/loopcaptain/mcp_server/__init__.py +0 -0
- loopcaptain-0.3.1/src/loopcaptain/mcp_server/server.py +181 -0
- loopcaptain-0.3.1/src/loopcaptain/prompts.py +27 -0
- loopcaptain-0.3.1/src/loopcaptain/protocol/AGENTS.md +24 -0
- loopcaptain-0.3.1/src/loopcaptain/protocol/__init__.py +17 -0
- loopcaptain-0.3.1/src/loopcaptain/protocol/doctor.py +79 -0
- loopcaptain-0.3.1/src/loopcaptain/protocol/models.py +496 -0
- loopcaptain-0.3.1/src/loopcaptain/protocol/signing.py +105 -0
- loopcaptain-0.3.1/src/loopcaptain/protocol/state.py +595 -0
- loopcaptain-0.3.1/src/loopcaptain/protocol/store.py +275 -0
- loopcaptain-0.3.1/src/loopcaptain/protocol/validate.py +199 -0
- loopcaptain-0.3.1/standard/AGENTS.md +207 -0
- loopcaptain-0.3.1/standard/LOOPS.md +402 -0
- loopcaptain-0.3.1/standard/loops.py +76 -0
- loopcaptain-0.3.1/standard/prompts/build-a-loop.md +6 -0
- loopcaptain-0.3.1/standard/prompts/watch-my-loops.md +6 -0
- loopcaptain-0.3.1/standard/schema/event.schema.json +1096 -0
- loopcaptain-0.3.1/standard/schema/inbox.schema.json +93 -0
- loopcaptain-0.3.1/standard/schema/loop.schema.json +296 -0
- loopcaptain-0.3.1/standard/templates/editor-maker-lens-loop.loop.json +25 -0
- loopcaptain-0.3.1/standard/templates/research-loop.loop.json +27 -0
- loopcaptain-0.3.1/standard/templates/review-loop.loop.json +20 -0
- loopcaptain-0.3.1/tests/__init__.py +0 -0
- loopcaptain-0.3.1/tests/conftest.py +103 -0
- loopcaptain-0.3.1/tests/test_agents.py +66 -0
- loopcaptain-0.3.1/tests/test_board.py +895 -0
- loopcaptain-0.3.1/tests/test_demo.py +119 -0
- loopcaptain-0.3.1/tests/test_docs.py +90 -0
- loopcaptain-0.3.1/tests/test_license.py +25 -0
- loopcaptain-0.3.1/tests/test_mcp.py +186 -0
- loopcaptain-0.3.1/tests/test_messages.py +59 -0
- loopcaptain-0.3.1/tests/test_neutral.py +96 -0
- loopcaptain-0.3.1/tests/test_protocol.py +523 -0
- loopcaptain-0.3.1/tests/test_protocol_growth.py +234 -0
- loopcaptain-0.3.1/tests/test_release.py +76 -0
- loopcaptain-0.3.1/tests/test_showcase.py +59 -0
- loopcaptain-0.3.1/uv.lock +1685 -0
- loopcaptain-0.3.1/zensical.toml +47 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Agent improvements
|
|
2
|
+
|
|
3
|
+
Evidence-backed proposals for how work in this repository is done. An
|
|
4
|
+
accepted one moves into its owner (AGENTS.md, a hook, a Makefile target)
|
|
5
|
+
and its row is deleted; the commit says where it went.
|
|
6
|
+
|
|
7
|
+
| # | Proposal | Evidence | Status |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| A2 | Run `ruff format` before string replacements in a file, or edit after formatting: the formatter rewraps lines and a replacement written against the old wrapping misses | Two replacement batches against `examples/demo_loop.py` failed on 2026-11-14 for this reason | open |
|
|
10
|
+
| A3 | Headless Chrome cannot render narrower than 500 px, so a `--window-size=390` screenshot shows a clipped desktop layout, not a phone. Check a phone with device emulation over the DevTools protocol, and make that a `make phone` target that fails when a page is wider than 390 px | The clipped 390 px shots of 2026-11-15 were the 500 px minimum; emulation found the real overflows (600eca2) | open |
|
|
11
|
+
| A4 | The shell here is bash 3.2: a command that mixes a heredoc with pipes or two heredocs is refused. Write a long commit message to a file and pass `-F <file>` | Several refused commits on 2026-11-15 | open |
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Deferred verification
|
|
2
|
+
|
|
3
|
+
Changes no real run has shown working yet. A row leaves when its evidence
|
|
4
|
+
is named in the commit that closes it.
|
|
5
|
+
|
|
6
|
+
| Commit | Change | Risk | Evidence that would close it |
|
|
7
|
+
|---|---|---|---|
|
|
8
|
+
| the MCP door | The MCP server ran over stdio against the SDK's own client (register, a round, a question, a refused call), not from a live agent session | An agent may use the tools differently than the docstrings intend, or skip calls | the server added as `loopcaptain mcp-config <agent>` prints, for two agents of different vendors, then one round reported from each session and seen on the board |
|
|
9
|
+
| the protocol | The example loop and one loop a fresh agent built from the first prompt (2026-11-15, validate ok, doctor passed, on the board) have written it; no real loop with real costs and long reviews has | Fields real rounds need may be missing; long summaries may crowd the round table | One round of a real loop (F1) shown on the board |
|
|
10
|
+
| the board | Looked at in Chrome, light and dark, at 1360 px, and at 390 px with device emulation (every page fits since 600eca2); not in Safari or Firefox, no keyboard-only pass, no automated accessibility run | Layout, focus or contrast faults outside Chrome | The pages opened in Safari and Firefox; a keyboard-only pass; a Lighthouse accessibility run |
|
|
11
|
+
| ci/hardening | The workflows (three Pythons and macOS, security, scorecard, links, release, docs) passed zizmor, actionlint and the workflow schema; none has run on GitHub | A runner difference, a missing environment or a Pages setting fails the first run | The branch pushed, CI green on a pull request; the docs workflow publishing once |
|
|
12
|
+
| the agents page | `docs/agents.md` follows a table read from each agent's documentation in the review of 2026-11-15; the entries for Gemini CLI, Cursor, opencode and Amp could not be confirmed in that review, and no line has been run | A wrong flag or file name sends a stranger the wrong way | The first prompt run in two agents of different vendors, each ending with a loop on the board |
|
|
13
|
+
| fix/board-message-codes | A loop page shows the green or red message only with a seal from this server process; tested through the app, not looked at on a running board | A message after a reply, stop or start no longer shows | `make demo`, `make serve`, press Stop on the example loop: the message shows; the same address with `note=` changed shows none |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Findings
|
|
2
|
+
|
|
3
|
+
Observations outside the task at hand. A row is recorded, a person
|
|
4
|
+
decides; a picked row moves to `docs/BACKLOG.md`, a settled one is deleted
|
|
5
|
+
in the commit that settles it. Proposed: now, later, check, drop.
|
|
6
|
+
|
|
7
|
+
| # | Finding | Status | Proposed | Evidence |
|
|
8
|
+
|---|---|---|---|---|
|
|
9
|
+
| F1 | The five loops this was designed around do not write `.loops/` yet. Each maps cleanly: (a) the two brief-and-lenses loops: BRIEF front matter -> `loop.json` (lenses -> review steps, `rounds` -> `round_cap`), `.rounds/N/plan.md` -> `round_started`, `lens-*.md` with its MATERIAL GAPS count -> `step_finished` findings, `cost.md` rows -> `cost`, `gate.md`, `verdict.md` and the thread entry -> `round_finished`, "Needs you" -> `question`, the thread's reply slot -> inbox; (b) the three research loops: `brief/brief.md` -> brief, `policy.py` reviewers and models -> steps, `work/rounds/N-worklist.yaml` -> `round_started`, `N-review-*.md` -> findings, `N-gate.md`, `N-verdict.md` -> `round_finished`, the approval file -> `question` | open | now, one loop first | the loops' round folders, read 2026-11-14 |
|
|
10
|
+
| F2 | The repository's home and name are not final. The connect sentence in `README.md` and `standard/AGENTS.md` says "the Loopcaptain repository" without an address, and the README has no CI badge | open | now, once the home is decided | README.md, standard/AGENTS.md |
|
|
11
|
+
| F5 | Protocol proposal: an optional `fingerprint` per finding (the helper computes it) so the board can follow one finding across rounds and show "open since round N"; replaces the rule that reviews are fresh each round where a loop sends it | open | later: the first thing after real loops are connected | published practice on review and gates, read 2026-11-14; docs/ARCHITECTURE.md section 7 |
|
|
12
|
+
| F7 | Protocol proposals to leave out of version 1: control role separate from activity, four severities with a separate blocking flag, lens criteria with ids, the gate declared as data, `done_when` checks, run ids, trigger, autonomy levels, SARIF export, a `by` on a closed finding. Each adds vocabulary a loop author must learn; unknown fields are allowed, so a loop can already carry them | open | drop for version 1, revisit with F5 | published loop tooling, read 2026-11-14; docs/ARCHITECTURE.md section 14 |
|
|
13
|
+
| F9 | A notification bridge (a phone message when a loop asks, a reply that lands in `inbox.jsonl`) would need an outside service and a rule for who may write the inbox | open | later | published human-in-the-loop tooling, read 2026-11-14 |
|
|
14
|
+
| F15 | An optional exporter that tails `events.jsonl` and sends OTLP along docs/opentelemetry.md: its own process and dependency group, off by default, the first thing that would send data off the machine | open | later: when someone wants loops beside agent traces | docs/ARCHITECTURE.md section 15 |
|
|
15
|
+
| F17 | The tab title counts what waits; the favicon does not. A count in the icon needs a drawn image per number or script | open | later | src/loopcaptain/board/templates/overview.html |
|
|
16
|
+
| F18 | A prompt to build a loop, given to a fresh agent, ended with a 302-line loop file for a three-step job; a smaller starting template (one loop.py of 60 lines beside the helper) would make the first loop cheaper | open | later: check with the next acceptance run | the acceptance run of 2026-11-15 |
|
|
17
|
+
| F19 | "Door" is used for the two ways a loop writes its files (the MCP server's docstring and so `docs/reference/mcp.md`, `mcp_server/AGENTS.md`, `standard/LOOPS.md` section 5). A reader new to the project does not know what a door is; the architecture heading and picture now say "ways in" and name the script and MCP | open | later: reword with the next change to those files, then `make docs-pages` | `git grep -n -i door`, 2026-11-15 |
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Upstream issues
|
|
2
|
+
|
|
3
|
+
Behaviour of external tools this repository works around. Filing upstream
|
|
4
|
+
is a public post and needs the person's yes.
|
|
5
|
+
|
|
6
|
+
| # | Upstream | Behaviour | Workaround | Report |
|
|
7
|
+
|---|---|---|---|---|
|
|
8
|
+
| U1 | `mcp` Python SDK 2.x | `FastMCP` was renamed to `MCPServer` (`mcp.server.mcpserver`); code written for 1.x fails on import | `pyproject.toml` requires `mcp>=2.0` and `mcp_server/server.py` imports `MCPServer` | none needed: documented in the SDK's migration guide |
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
|
|
9
|
+
[*.py]
|
|
10
|
+
indent_style = space
|
|
11
|
+
indent_size = 4
|
|
12
|
+
|
|
13
|
+
[*.{yml,yaml,json,toml}]
|
|
14
|
+
indent_style = space
|
|
15
|
+
indent_size = 2
|
|
16
|
+
|
|
17
|
+
[Makefile]
|
|
18
|
+
indent_style = tab
|
|
19
|
+
|
|
20
|
+
[*.{md,tex}]
|
|
21
|
+
indent_style = space
|
|
22
|
+
indent_size = 2
|
|
23
|
+
trim_trailing_whitespace = false
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Both are optional. The board runs without a .env file.
|
|
2
|
+
|
|
3
|
+
# Path of the config that lists the watched repositories.
|
|
4
|
+
# Default: loopcaptain.local.yaml in the folder the board is started in.
|
|
5
|
+
LOOPCAPTAIN_CONFIG=
|
|
6
|
+
|
|
7
|
+
# Folder for the pid records and logs of loops the board started.
|
|
8
|
+
# Default: .state in the folder the board is started in.
|
|
9
|
+
LOOPCAPTAIN_STATE=
|
|
10
|
+
|
|
11
|
+
# Folders, separated by ":", under which the MCP tools may write besides the
|
|
12
|
+
# folder the server was started in.
|
|
13
|
+
LOOPCAPTAIN_MCP_ROOTS=
|
|
14
|
+
|
|
15
|
+
# The key the board signs inbox lines with. Default: ~/.config/loopcaptain/inbox.key
|
|
16
|
+
LOOPCAPTAIN_INBOX_KEY=
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Something is wrong
|
|
2
|
+
description: The board, the command line or the MCP server does not do what it should.
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: what
|
|
7
|
+
attributes:
|
|
8
|
+
label: What happened, and what you expected
|
|
9
|
+
validations:
|
|
10
|
+
required: true
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: steps
|
|
13
|
+
attributes:
|
|
14
|
+
label: How to see it
|
|
15
|
+
description: The commands, the page, and a few lines of the loop's files if they matter. Invent the content; never paste a real loop's text.
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: input
|
|
19
|
+
id: version
|
|
20
|
+
attributes:
|
|
21
|
+
label: Version
|
|
22
|
+
description: "`loopcaptain --version` or the commit"
|
|
23
|
+
- type: input
|
|
24
|
+
id: system
|
|
25
|
+
attributes:
|
|
26
|
+
label: System and browser
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: A security problem
|
|
4
|
+
url: https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability
|
|
5
|
+
about: Report it privately through this repository's security advisories, not as an issue.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: A loop does not show up
|
|
2
|
+
description: A loop writes .loops/ but the board does not show it, or shows it wrong.
|
|
3
|
+
labels: [connect]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: validate
|
|
7
|
+
attributes:
|
|
8
|
+
label: What `loopcaptain validate <repository>` prints
|
|
9
|
+
render: text
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: config
|
|
14
|
+
attributes:
|
|
15
|
+
label: How the board watches the repository
|
|
16
|
+
description: The roots and repos entries, with your own folder names replaced.
|
|
17
|
+
render: yaml
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: what
|
|
20
|
+
attributes:
|
|
21
|
+
label: What you expected to see
|
|
22
|
+
validations:
|
|
23
|
+
required: true
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: A protocol proposal
|
|
2
|
+
description: A field or an event the Loops protocol lacks.
|
|
3
|
+
labels: [protocol]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: need
|
|
7
|
+
attributes:
|
|
8
|
+
label: What a real loop could not say
|
|
9
|
+
description: The loop, in invented words, and what it had to do instead.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: The field or event, as a line of events.jsonl
|
|
16
|
+
render: json
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: checkboxes
|
|
20
|
+
id: grows
|
|
21
|
+
attributes:
|
|
22
|
+
label: Protocol 1 only grows
|
|
23
|
+
options:
|
|
24
|
+
- label: The proposal is optional; a loop written against today's text still validates.
|
|
25
|
+
required: true
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: uv
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: monthly
|
|
7
|
+
cooldown:
|
|
8
|
+
default-days: 7
|
|
9
|
+
semver-major-days: 14
|
|
10
|
+
groups:
|
|
11
|
+
python:
|
|
12
|
+
patterns: ["*"]
|
|
13
|
+
- package-ecosystem: github-actions
|
|
14
|
+
directory: /
|
|
15
|
+
schedule:
|
|
16
|
+
interval: monthly
|
|
17
|
+
cooldown:
|
|
18
|
+
default-days: 7
|
|
19
|
+
semver-major-days: 14
|
|
20
|
+
groups:
|
|
21
|
+
actions:
|
|
22
|
+
patterns: ["*"]
|
|
23
|
+
- package-ecosystem: pre-commit
|
|
24
|
+
directory: /
|
|
25
|
+
schedule:
|
|
26
|
+
interval: monthly
|
|
27
|
+
cooldown:
|
|
28
|
+
default-days: 7
|
|
29
|
+
semver-major-days: 14
|
|
30
|
+
groups:
|
|
31
|
+
hooks:
|
|
32
|
+
patterns: ["*"]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- The title is a commit subject: type(scope): subject. Write about the change, never about the
|
|
2
|
+
conversation that led to it: no "as requested", no "the user wants". AGENTS.md has the rules. -->
|
|
3
|
+
|
|
4
|
+
## What changes for a user
|
|
5
|
+
|
|
6
|
+
<!-- One or two sentences. The subjects of the feat, fix and perf commits become the release notes. -->
|
|
7
|
+
|
|
8
|
+
## Why
|
|
9
|
+
|
|
10
|
+
<!-- The problem, with evidence: an issue, a finding, a run. -->
|
|
11
|
+
|
|
12
|
+
## Done when
|
|
13
|
+
|
|
14
|
+
- [ ] A test fails without this change, and `make check` is green.
|
|
15
|
+
- [ ] Looked at for real (`make demo`, `make serve`), or listed in `.agent/DEFERRED_VERIFICATION.md`.
|
|
16
|
+
- [ ] Text, models and schema of the standard agree (`make schema`), if the protocol changed.
|
|
17
|
+
- [ ] `feat`, `fix` and `perf` subjects read as lines of release notes; a decision has its section in `docs/ARCHITECTURE.md`.
|
|
18
|
+
- [ ] Nothing names a company, a client or a real loop.
|
|
19
|
+
- [ ] The title and this text describe the change, not the conversation that led to it.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: CI
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions: {}
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
# Actions are pinned to commits, not tags: a tag can be moved onto other code.
|
|
18
|
+
# The comment names the release for the human reading it.
|
|
19
|
+
jobs:
|
|
20
|
+
check:
|
|
21
|
+
name: make check (${{ matrix.os }}, Python ${{ matrix.python }})
|
|
22
|
+
runs-on: ${{ matrix.os }}
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
strategy:
|
|
26
|
+
fail-fast: false
|
|
27
|
+
matrix:
|
|
28
|
+
os: [ubuntu-latest]
|
|
29
|
+
python: ["3.12", "3.13", "3.14"]
|
|
30
|
+
include:
|
|
31
|
+
# The board starts processes and reads process groups: check it where people run it.
|
|
32
|
+
- os: macos-latest
|
|
33
|
+
python: "3.12"
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
36
|
+
with:
|
|
37
|
+
persist-credentials: false
|
|
38
|
+
|
|
39
|
+
- name: Install uv
|
|
40
|
+
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
41
|
+
with:
|
|
42
|
+
python-version: ${{ matrix.python }}
|
|
43
|
+
|
|
44
|
+
- name: Install
|
|
45
|
+
run: uv sync --frozen
|
|
46
|
+
|
|
47
|
+
# No model and no network: the tests run the example loop, which calls no agent.
|
|
48
|
+
- name: Check
|
|
49
|
+
run: make check
|
|
50
|
+
env:
|
|
51
|
+
UV_NO_SYNC: "1"
|
|
52
|
+
|
|
53
|
+
secrets:
|
|
54
|
+
name: gitleaks
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
permissions:
|
|
57
|
+
contents: read
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
60
|
+
with:
|
|
61
|
+
fetch-depth: 0 # a secret committed once and reverted is still leaked
|
|
62
|
+
persist-credentials: false
|
|
63
|
+
|
|
64
|
+
# The gitleaks CLI directly, pinned by digest: the same release as the pre-commit hook.
|
|
65
|
+
- name: Scan history for secrets
|
|
66
|
+
run: >-
|
|
67
|
+
docker run --rm -v "$PWD:/repo"
|
|
68
|
+
ghcr.io/gitleaks/gitleaks:v8.30.1@sha256:c00b6bd0aeb3071cbcb79009cb16a60dd9e0a7c60e2be9ab65d25e6bc8abbb7f
|
|
69
|
+
git /repo --redact --verbose --exit-code 1
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
|
|
3
|
+
# Builds the documentation site on every change to main, and publishes it to GitHub Pages with
|
|
4
|
+
# the official flow only when the repository variable PUBLISH_DOCS is "true". A Pages site is
|
|
5
|
+
# public even when the repository is private, so publishing waits for the decision to go public.
|
|
6
|
+
# Only the deploy job may write to Pages or mint an identity token, in the `github-pages`
|
|
7
|
+
# environment. No versioned docs before 1.0.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: [main]
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
permissions: {}
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: pages
|
|
18
|
+
cancel-in-progress: false
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
27
|
+
with:
|
|
28
|
+
persist-credentials: false
|
|
29
|
+
|
|
30
|
+
- uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.12"
|
|
33
|
+
|
|
34
|
+
- name: Build
|
|
35
|
+
run: |
|
|
36
|
+
uv sync --frozen
|
|
37
|
+
uv run --group docs zensical build --clean
|
|
38
|
+
cp docs/llms.txt site/llms.txt
|
|
39
|
+
|
|
40
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
41
|
+
with:
|
|
42
|
+
path: site/
|
|
43
|
+
|
|
44
|
+
deploy:
|
|
45
|
+
needs: build
|
|
46
|
+
if: vars.PUBLISH_DOCS == 'true'
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
environment:
|
|
49
|
+
name: github-pages
|
|
50
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
51
|
+
permissions:
|
|
52
|
+
pages: write
|
|
53
|
+
id-token: write
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
|
56
|
+
- id: deployment
|
|
57
|
+
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: links
|
|
2
|
+
|
|
3
|
+
# Weekly: do the links in the documents still lead somewhere? Never a gate: a site that is down
|
|
4
|
+
# for an hour must not block a change. A failure opens nothing; read the run.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: "41 6 * * 1"
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions: {}
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
check:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
20
|
+
with:
|
|
21
|
+
persist-credentials: false
|
|
22
|
+
- uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0
|
|
23
|
+
with:
|
|
24
|
+
args: >-
|
|
25
|
+
--no-progress --max-retries 3
|
|
26
|
+
--exclude '^https?://127\.0\.0\.1'
|
|
27
|
+
'./**/*.md'
|
|
28
|
+
fail: true
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: pr-description
|
|
2
|
+
|
|
3
|
+
# The commit-msg hooks keep AI attribution and conversation out of commits and hold the subject
|
|
4
|
+
# to Conventional Commits, but nothing local ever sees a pull request's title or description.
|
|
5
|
+
# This runs the same hooks on both, so each pattern lives in one place
|
|
6
|
+
# (.pre-commit-config.yaml). Separate from ci.yml so editing a description re-runs
|
|
7
|
+
# only this, not the whole gate.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
pull_request:
|
|
11
|
+
types: [opened, edited, reopened, synchronize]
|
|
12
|
+
|
|
13
|
+
permissions: {}
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
attribution:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
22
|
+
with:
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
|
|
25
|
+
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
26
|
+
with:
|
|
27
|
+
python-version: '3.12'
|
|
28
|
+
|
|
29
|
+
# Through env, never interpolated into the script: the description is untrusted text.
|
|
30
|
+
- name: Write the PR description to a file
|
|
31
|
+
env:
|
|
32
|
+
BODY: ${{ github.event.pull_request.body }}
|
|
33
|
+
run: printf '%s\n' "$BODY" > "$RUNNER_TEMP/pr-description.txt"
|
|
34
|
+
|
|
35
|
+
- name: Reject AI attribution in the PR description
|
|
36
|
+
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
|
37
|
+
with:
|
|
38
|
+
extra_args: >-
|
|
39
|
+
no-agent-coauthors --hook-stage commit-msg
|
|
40
|
+
--commit-msg-filename ${{ runner.temp }}/pr-description.txt
|
|
41
|
+
|
|
42
|
+
# The description is about the change, never about the conversation that led to it
|
|
43
|
+
# (AGENTS.md, "Commits and pull requests").
|
|
44
|
+
- name: Reject conversation in the PR description
|
|
45
|
+
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
|
46
|
+
with:
|
|
47
|
+
extra_args: >-
|
|
48
|
+
no-conversation --hook-stage commit-msg
|
|
49
|
+
--commit-msg-filename ${{ runner.temp }}/pr-description.txt
|
|
50
|
+
|
|
51
|
+
# The title becomes a line of the changelog when a pull request is squashed.
|
|
52
|
+
- name: Write the PR title to a file
|
|
53
|
+
env:
|
|
54
|
+
TITLE: ${{ github.event.pull_request.title }}
|
|
55
|
+
run: printf '%s\n' "$TITLE" > "$RUNNER_TEMP/pr-title.txt"
|
|
56
|
+
|
|
57
|
+
- name: The PR title is a Conventional Commit subject
|
|
58
|
+
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
|
59
|
+
with:
|
|
60
|
+
extra_args: >-
|
|
61
|
+
conventional-commit --hook-stage commit-msg
|
|
62
|
+
--commit-msg-filename ${{ runner.temp }}/pr-title.txt
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# Every push to main that brings a feat, fix or perf commit gets the next version as a tag and a
|
|
4
|
+
# GitHub release, with those commits as its notes and the built wheel attached
|
|
5
|
+
# (scripts/release.py, docs/ARCHITECTURE.md section 19). Nothing is committed back, so nobody
|
|
6
|
+
# bumps a version, pushes a tag or opens a pull request for one. The wheel is stamped with the
|
|
7
|
+
# tag's version in the runner, proved to work installed outside a checkout, and published to PyPI
|
|
8
|
+
# by trusted publishing (no token stored anywhere) once the repository variable PUBLISH_PYPI is
|
|
9
|
+
# "true".
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
branches: [main]
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
permissions: {}
|
|
17
|
+
|
|
18
|
+
# One release at a time, in push order, so two merges never take the same tag.
|
|
19
|
+
concurrency:
|
|
20
|
+
group: release
|
|
21
|
+
cancel-in-progress: false
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
release:
|
|
25
|
+
name: tag and release
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
timeout-minutes: 15
|
|
28
|
+
permissions:
|
|
29
|
+
contents: write # the tag and the release
|
|
30
|
+
outputs:
|
|
31
|
+
tag: ${{ steps.next.outputs.tag }}
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
34
|
+
with:
|
|
35
|
+
fetch-depth: 0 # every tag and the commits since the last one
|
|
36
|
+
persist-credentials: false
|
|
37
|
+
|
|
38
|
+
- uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
39
|
+
with:
|
|
40
|
+
python-version: "3.12"
|
|
41
|
+
|
|
42
|
+
- name: Next version
|
|
43
|
+
id: next
|
|
44
|
+
run: echo "tag=$(uv run --no-project python scripts/release.py --notes "$RUNNER_TEMP/release-notes.md")" >> "$GITHUB_OUTPUT"
|
|
45
|
+
|
|
46
|
+
- name: Stamp the version and build
|
|
47
|
+
if: steps.next.outputs.tag != ''
|
|
48
|
+
env:
|
|
49
|
+
TAG: ${{ steps.next.outputs.tag }}
|
|
50
|
+
run: |
|
|
51
|
+
uv version "${TAG#v}"
|
|
52
|
+
uv build
|
|
53
|
+
|
|
54
|
+
- name: Install the wheel in a clean environment and use it
|
|
55
|
+
if: steps.next.outputs.tag != ''
|
|
56
|
+
env:
|
|
57
|
+
TAG: ${{ steps.next.outputs.tag }}
|
|
58
|
+
run: |
|
|
59
|
+
uv venv /tmp/clean
|
|
60
|
+
uv pip install --python /tmp/clean/bin/python dist/*.whl
|
|
61
|
+
cd /tmp
|
|
62
|
+
test "$(/tmp/clean/bin/loopcaptain --version)" = "loopcaptain ${TAG#v}"
|
|
63
|
+
/tmp/clean/bin/loopcaptain spec > /dev/null
|
|
64
|
+
/tmp/clean/bin/loopcaptain demo --target /tmp/demo --no-watch
|
|
65
|
+
/tmp/clean/bin/loopcaptain validate --strict /tmp/demo
|
|
66
|
+
|
|
67
|
+
- name: Tag and release
|
|
68
|
+
if: steps.next.outputs.tag != ''
|
|
69
|
+
env:
|
|
70
|
+
GH_TOKEN: ${{ github.token }}
|
|
71
|
+
GH_REPO: ${{ github.repository }}
|
|
72
|
+
TAG: ${{ steps.next.outputs.tag }}
|
|
73
|
+
run: >-
|
|
74
|
+
gh release create "$TAG" dist/*.whl dist/*.tar.gz --target "$GITHUB_SHA" --title "$TAG"
|
|
75
|
+
--notes-file "$RUNNER_TEMP/release-notes.md"
|
|
76
|
+
|
|
77
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
78
|
+
if: steps.next.outputs.tag != ''
|
|
79
|
+
with:
|
|
80
|
+
name: dist
|
|
81
|
+
path: |
|
|
82
|
+
dist/*.whl
|
|
83
|
+
dist/*.tar.gz
|
|
84
|
+
if-no-files-found: error
|
|
85
|
+
|
|
86
|
+
publish:
|
|
87
|
+
needs: release
|
|
88
|
+
if: needs.release.outputs.tag != '' && vars.PUBLISH_PYPI == 'true'
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
environment: pypi
|
|
91
|
+
permissions:
|
|
92
|
+
id-token: write # trusted publishing to PyPI
|
|
93
|
+
attestations: write # build provenance
|
|
94
|
+
contents: read
|
|
95
|
+
steps:
|
|
96
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
97
|
+
with:
|
|
98
|
+
name: dist
|
|
99
|
+
path: dist/
|
|
100
|
+
|
|
101
|
+
- uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
|
102
|
+
with:
|
|
103
|
+
subject-path: dist/*
|
|
104
|
+
|
|
105
|
+
- uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
106
|
+
|
|
107
|
+
- name: Publish
|
|
108
|
+
run: uv publish --trusted-publishing always dist/*
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: scorecard
|
|
2
|
+
|
|
3
|
+
# The OpenSSF Scorecard, weekly: how the repository's own practices look to a stranger who has
|
|
4
|
+
# to decide whether to trust it. Results go to the code scanning tab, never block a change.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: "17 5 * * 1"
|
|
9
|
+
push:
|
|
10
|
+
branches: [main]
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
permissions: {}
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
analysis:
|
|
17
|
+
# The Scorecard reads a repository as a stranger would, so it runs only once it is public.
|
|
18
|
+
if: ${{ !github.event.repository.private }}
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
security-events: write
|
|
23
|
+
id-token: write # publishes the result to the OpenSSF API
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
28
|
+
- uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0
|
|
29
|
+
with:
|
|
30
|
+
results_file: results.sarif
|
|
31
|
+
results_format: sarif
|
|
32
|
+
publish_results: true
|
|
33
|
+
- uses: github/codeql-action/upload-sarif@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3
|
|
34
|
+
with:
|
|
35
|
+
sarif_file: results.sarif
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: security
|
|
2
|
+
|
|
3
|
+
# What the code review of a workflow and a dependency cannot see by eye: zizmor reads every
|
|
4
|
+
# workflow for injection and credential leaks; dependency review refuses a pull request that adds
|
|
5
|
+
# a dependency with a known vulnerability. CodeQL runs by GitHub's default setup, a repository
|
|
6
|
+
# setting, not a workflow.
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches: [main]
|
|
11
|
+
pull_request:
|
|
12
|
+
branches: [main]
|
|
13
|
+
|
|
14
|
+
permissions: {}
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
zizmor:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
23
|
+
with:
|
|
24
|
+
persist-credentials: false
|
|
25
|
+
- uses: zizmorcore/zizmor-action@45d7276c9ca790aabd705e31ca99c6185c3e76dd # v0.8.1
|
|
26
|
+
with:
|
|
27
|
+
advanced-security: false
|
|
28
|
+
|
|
29
|
+
dependencies:
|
|
30
|
+
if: github.event_name == 'pull_request'
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
permissions:
|
|
33
|
+
contents: read
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
|
|
36
|
+
with:
|
|
37
|
+
fail-on-severity: moderate
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Finder and editor clutter
|
|
2
|
+
.DS_Store
|
|
3
|
+
/.serena/
|
|
4
|
+
|
|
5
|
+
# Environments, caches, coverage
|
|
6
|
+
/.venv/
|
|
7
|
+
__pycache__/
|
|
8
|
+
/.pytest_cache/
|
|
9
|
+
/.mypy_cache/
|
|
10
|
+
/.ruff_cache/
|
|
11
|
+
/.coverage
|
|
12
|
+
/site/
|
|
13
|
+
|
|
14
|
+
# Secrets
|
|
15
|
+
/.env
|
|
16
|
+
|
|
17
|
+
# Which repositories this laptop's board watches, the demo loop's working
|
|
18
|
+
# folder, and the logs of processes the board started
|
|
19
|
+
*.local
|
|
20
|
+
*.local.md
|
|
21
|
+
*.local.yaml
|
|
22
|
+
/demo/
|
|
23
|
+
/.state/
|