clauster 0.2.2__tar.gz → 0.3.0__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.
- {clauster-0.2.2 → clauster-0.3.0}/.bestpractices.json +1 -1
- clauster-0.3.0/.coderabbit.yaml +54 -0
- clauster-0.3.0/.github/ISSUE_TEMPLATE/bug_report.yml +56 -0
- clauster-0.3.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- clauster-0.3.0/.github/ISSUE_TEMPLATE/feature_request.yml +21 -0
- clauster-0.3.0/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- clauster-0.3.0/.github/repo-config/labels.json +15 -0
- clauster-0.3.0/.github/rulesets/README.md +63 -0
- clauster-0.3.0/.github/rulesets/main.json +53 -0
- clauster-0.3.0/.github/rulesets/tags.json +16 -0
- {clauster-0.2.2 → clauster-0.3.0}/.github/workflows/lint.yml +2 -1
- clauster-0.3.0/.release-please-manifest.json +3 -0
- {clauster-0.2.2 → clauster-0.3.0}/.yamllint.yaml +1 -1
- {clauster-0.2.2 → clauster-0.3.0}/CHANGELOG.md +15 -0
- {clauster-0.2.2 → clauster-0.3.0}/PKG-INFO +44 -3
- {clauster-0.2.2 → clauster-0.3.0}/README.md +43 -2
- clauster-0.3.0/compose.yaml +38 -0
- {clauster-0.2.2 → clauster-0.3.0}/pyproject.toml +1 -1
- {clauster-0.2.2 → clauster-0.3.0}/renovate.json +16 -6
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/__init__.py +1 -1
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/config.py +1 -4
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/ops.py +49 -1
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/redact.py +8 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/runner.py +50 -5
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/templates/dashboard.html +7 -1
- {clauster-0.2.2 → clauster-0.3.0}/tests/E2E_CHECKLIST.md +9 -3
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_app.py +12 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_clone_jobs.py +2 -1
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_ops.py +48 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_redact.py +39 -4
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_runner.py +56 -0
- {clauster-0.2.2 → clauster-0.3.0}/uv.lock +1 -1
- clauster-0.2.2/.coderabbit.yaml +0 -17
- clauster-0.2.2/.github/settings.yml +0 -143
- clauster-0.2.2/.release-please-manifest.json +0 -3
- {clauster-0.2.2 → clauster-0.3.0}/.dockerignore +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/.github/CODEOWNERS +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/.github/workflows/ci.yml +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/.github/workflows/pr-title.yml +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/.github/workflows/release-please.yml +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/.github/workflows/release.yml +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/.github/workflows/scorecard.yml +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/.github/workflows/security.yml +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/.gitignore +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/.markdownlint-cli2.yaml +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/.pre-commit-config.yaml +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/CONTRIBUTING.md +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/Dockerfile +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/LICENSE +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/SECURITY.md +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/THIRD_PARTY_NOTICES.md +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/UPGRADING.md +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/clauster.spec +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/clauster.yml.example +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/codecov.yml +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/docker/entrypoint.sh +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/docs/screenshots/dashboard-dark.png +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/docs/screenshots/dashboard-light.png +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/docs/screenshots/login-dark.png +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/docs/screenshots/new-project-clone.png +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/package-lock.json +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/package.json +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/release-please-config.json +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/scripts/build-binary.sh +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/scripts/lint-docs.sh +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/__main__.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/app.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/auth.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/bridge_log.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/claude_cli.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/claude_md.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/clone_jobs.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/discovery.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/environments.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/hooks/__init__.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/hooks/resume_recap.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/inspector.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/logstream.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/models.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/pointers.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/procutil.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/provisioning.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/pty_keeper.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/recap.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/state.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/alpine.LICENSE +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/alpine.min.js +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/clauster.css +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/favicon.svg +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/vendor/iconoir/LICENSE +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/vendor/iconoir/README.md +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/vendor/tabler/LICENSE +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/vendor/tabler/README.md +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/vendor/tabler/css/tabler.min.css +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/vendor/tabler/js/tabler.min.js +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/static/vendor/versions.txt +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/templates/_iconoir_sprite.html +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/templates/_project_card.html +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/templates/login.html +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/trust.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/src/clauster/usage.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/conftest.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/fixtures/bridge-logs/test1-bridge-debug.log +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/fixtures/fake_claude/claude +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/fixtures/fake_claude/claude.cmd +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/fixtures/fake_git/git +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/fixtures/fake_git/git.cmd +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/fixtures/pointers/dockerize2.bridge-pointer.json +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/fixtures/pointers/test1.bridge-pointer.json +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/fixtures/pointers/test2.bridge-pointer.json +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/fixtures/transcripts/test1-session.jsonl +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_app_auth.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_app_instances.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_app_routes.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_auth.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_bridge_log.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_claude_md.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_config.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_discovery.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_environments.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_fixtures.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_inspector.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_logstream.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_logtail.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_main.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_pointers.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_procutil.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_provisioning.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_pty_keeper.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_recap.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_runner_pty.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_runner_recap.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_spawn_controls.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_state.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_trust.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_urls.py +0 -0
- {clauster-0.2.2 → clauster-0.3.0}/tests/test_usage.py +0 -0
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"vulnerabilities_fixed_60_days_status": "Met",
|
|
115
115
|
"vulnerabilities_fixed_60_days_justification": "Renovate and GitHub security alerts surface dependency vulnerabilities, which are patched promptly (well within 60 days).",
|
|
116
116
|
"vulnerabilities_critical_fixed_status": "Met",
|
|
117
|
-
"vulnerabilities_critical_fixed_justification": "No known unpatched vulnerabilities exist
|
|
117
|
+
"vulnerabilities_critical_fixed_justification": "No known unpatched vulnerabilities exist; the OpenSSF Scorecard Vulnerabilities check runs on pushes to main and on a weekly schedule, and dependency alerts (Renovate + GitHub) surface any new ones for prompt patching.",
|
|
118
118
|
"no_leaked_credentials_status": "Met",
|
|
119
119
|
"no_leaked_credentials_justification": "No credentials are stored in the repository; gitleaks and GitHub secret scanning run in CI, sensitive config is gitignored, and session URLs/tokens are redacted in logs.",
|
|
120
120
|
"static_analysis_status": "Met",
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
|
|
2
|
+
# CodeRabbit configuration. Schema: https://www.coderabbit.ai/integrations/schema.v2.json
|
|
3
|
+
#
|
|
4
|
+
# Docstrings: our gate is ruff's pydocstyle (D) rules, enforced on EVERY PR by the
|
|
5
|
+
# "lint" CI job (.github/workflows/lint.yml, `on: pull_request`). It requires
|
|
6
|
+
# docstrings on all public modules/classes/functions (pep257 convention; D105/D107
|
|
7
|
+
# and tests/** are intentionally exempt — see pyproject.toml).
|
|
8
|
+
#
|
|
9
|
+
# CodeRabbit's separate docstring-coverage pre-merge check computes a raw
|
|
10
|
+
# percentage that counts inner/nested helpers (preexec closures, signal handlers,
|
|
11
|
+
# test fixtures) which our gate deliberately exempts, so it reports a misleadingly
|
|
12
|
+
# low number against its 80% default. Defer to ruff D as the single source of
|
|
13
|
+
# truth and turn the redundant check off rather than run two disagreeing gates.
|
|
14
|
+
language: "en-US"
|
|
15
|
+
reviews:
|
|
16
|
+
profile: "chill"
|
|
17
|
+
# Don't gate merges on a CodeRabbit "request changes" state — it isn't a
|
|
18
|
+
# required check and we don't want it blocking the solo merge flow.
|
|
19
|
+
request_changes_workflow: false
|
|
20
|
+
high_level_summary: true
|
|
21
|
+
poem: false
|
|
22
|
+
review_status: true
|
|
23
|
+
pre_merge_checks:
|
|
24
|
+
docstrings:
|
|
25
|
+
mode: "off"
|
|
26
|
+
auto_review:
|
|
27
|
+
enabled: true
|
|
28
|
+
drafts: false
|
|
29
|
+
# Skip bot-authored PRs (Renovate, release-please). They only touch deps /
|
|
30
|
+
# CHANGELOG / version files, and skipping them lets auto-merge proceed without
|
|
31
|
+
# waiting on review-thread resolution (the `main` ruleset requires it).
|
|
32
|
+
ignore_usernames:
|
|
33
|
+
- "renovate[bot]"
|
|
34
|
+
- "clauster-release-bot[bot]"
|
|
35
|
+
# Don't spend review effort on vendored / generated / lockfile content.
|
|
36
|
+
path_filters:
|
|
37
|
+
- "!src/clauster/static/vendor/**"
|
|
38
|
+
- "!**/*.min.js"
|
|
39
|
+
- "!**/*.min.css"
|
|
40
|
+
- "!uv.lock"
|
|
41
|
+
- "!package-lock.json"
|
|
42
|
+
path_instructions:
|
|
43
|
+
- path: "src/clauster/templates/**"
|
|
44
|
+
instructions: >-
|
|
45
|
+
These are Jinja2 templates (autoescape on) driving Alpine.js. Values
|
|
46
|
+
rendered with {{ }} are HTML-escaped by default — don't flag ordinary
|
|
47
|
+
interpolation as XSS. Only raw / `| safe` output, or interpolation into
|
|
48
|
+
event-handler attributes / inline script, is a genuine concern.
|
|
49
|
+
- path: "tests/**"
|
|
50
|
+
instructions: >-
|
|
51
|
+
Tests use FastAPI's TestClient. WebSocket and background-task tests must
|
|
52
|
+
wrap the client in `with _client(...)` so the app lifespan/startup runs.
|
|
53
|
+
chat:
|
|
54
|
+
auto_reply: true
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something in Clauster isn't working as expected
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: >
|
|
8
|
+
Thanks for taking the time to file a bug. **For security vulnerabilities,
|
|
9
|
+
do not open an issue** — report it privately via a
|
|
10
|
+
[GitHub Security Advisory](https://github.com/schubydoo/clauster/security/advisories/new)
|
|
11
|
+
(see [SECURITY.md](https://github.com/schubydoo/clauster/blob/main/SECURITY.md)).
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: what-happened
|
|
14
|
+
attributes:
|
|
15
|
+
label: What happened?
|
|
16
|
+
description: A clear description of the bug, including what you expected instead.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: repro
|
|
21
|
+
attributes:
|
|
22
|
+
label: Steps to reproduce
|
|
23
|
+
placeholder: |
|
|
24
|
+
1. ...
|
|
25
|
+
2. ...
|
|
26
|
+
3. ...
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
- type: input
|
|
30
|
+
id: version
|
|
31
|
+
attributes:
|
|
32
|
+
label: Clauster version
|
|
33
|
+
description: Output of `clauster --version`, or the Docker image tag.
|
|
34
|
+
validations:
|
|
35
|
+
required: true
|
|
36
|
+
- type: dropdown
|
|
37
|
+
id: install
|
|
38
|
+
attributes:
|
|
39
|
+
label: Install method
|
|
40
|
+
options:
|
|
41
|
+
- pip / uv (PyPI)
|
|
42
|
+
- Docker (GHCR)
|
|
43
|
+
- from source
|
|
44
|
+
validations:
|
|
45
|
+
required: true
|
|
46
|
+
- type: textarea
|
|
47
|
+
id: env
|
|
48
|
+
attributes:
|
|
49
|
+
label: Environment
|
|
50
|
+
description: OS, Python version, browser (for a UI bug), reverse proxy (if any).
|
|
51
|
+
- type: textarea
|
|
52
|
+
id: logs
|
|
53
|
+
attributes:
|
|
54
|
+
label: Relevant logs
|
|
55
|
+
description: Paste `clauster` output or bridge logs. Redact any tokens or secrets.
|
|
56
|
+
render: shell
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Security vulnerability (report privately)
|
|
4
|
+
url: https://github.com/schubydoo/clauster/security/advisories/new
|
|
5
|
+
about: Please report security issues privately via a GitHub Security Advisory — do not open a public issue.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an idea or improvement
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem / motivation
|
|
9
|
+
description: What are you trying to do that Clauster doesn't support today?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: Proposed solution
|
|
16
|
+
description: What would you like to see happen?
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: alternatives
|
|
19
|
+
attributes:
|
|
20
|
+
label: Alternatives considered
|
|
21
|
+
description: Other approaches or workarounds you've tried or thought about.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!-- markdownlint-disable-file -->
|
|
2
|
+
|
|
3
|
+
## What
|
|
4
|
+
|
|
5
|
+
<!-- What does this PR change, and why? Link any related issue. -->
|
|
6
|
+
|
|
7
|
+
## Checklist
|
|
8
|
+
|
|
9
|
+
- [ ] PR title follows [Conventional Commits](https://www.conventionalcommits.org/) — it becomes the squashed commit subject that release-please parses (and the required `conventional PR title` check gates it).
|
|
10
|
+
- [ ] Tests added/updated for the change (the `tests` check enforces a 96% coverage gate).
|
|
11
|
+
- [ ] Docs / README updated where user-facing behaviour or config changed.
|
|
12
|
+
- [ ] `uv run pytest` and `uv run pre-commit run -a` pass locally.
|
|
13
|
+
|
|
14
|
+
<!-- The CHANGELOG is generated from commit history by release-please — no manual CHANGELOG edits are needed. -->
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[
|
|
2
|
+
{ "name": "bug", "color": "d73a4a", "description": "Something isn't working" },
|
|
3
|
+
{ "name": "enhancement", "color": "a2eeef", "description": "New feature or request" },
|
|
4
|
+
{ "name": "documentation", "color": "0075ca", "description": "Improvements or additions to documentation" },
|
|
5
|
+
{ "name": "question", "color": "d876e3", "description": "Further information is requested" },
|
|
6
|
+
{ "name": "good first issue", "color": "7057ff", "description": "Good for newcomers" },
|
|
7
|
+
{ "name": "help wanted", "color": "008672", "description": "Extra attention is needed" },
|
|
8
|
+
{ "name": "breaking", "color": "b60205", "description": "Backwards-incompatible change" },
|
|
9
|
+
{ "name": "security", "color": "d93f0b", "description": "Security-related — Renovate vulnerability alerts use this" },
|
|
10
|
+
{ "name": "dependencies", "color": "ededed", "description": "Renovate-opened dependency update PRs (and the dashboard issue)" },
|
|
11
|
+
{ "name": "vendored-assets", "color": "ededed", "description": "Renovate heads-up to re-vendor self-hosted front-end assets (manual dist update)" },
|
|
12
|
+
{ "name": "autorelease: pending", "color": "ededed", "description": "Release Please — release PR is open, awaiting merge" },
|
|
13
|
+
{ "name": "autorelease: tagged", "color": "0e8a16", "description": "Release Please — release PR is merged and the tag has been pushed" },
|
|
14
|
+
{ "name": "autorelease: snapshot", "color": "5319e7", "description": "Release Please — snapshot/prerelease (rare)" }
|
|
15
|
+
]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Repository rulesets
|
|
2
|
+
|
|
3
|
+
`main.json` is the source-of-truth for the **`main` branch ruleset** — the
|
|
4
|
+
replacement for the legacy branch-protection rules previously declared in
|
|
5
|
+
`.github/settings.yml` and reconciled by the [`repository-settings`][app] Probot
|
|
6
|
+
app. That config file is removed in this PR, and the app itself has been
|
|
7
|
+
uninstalled from the repository — the ruleset is now the sole source of branch
|
|
8
|
+
protection.
|
|
9
|
+
|
|
10
|
+
It encodes the same contract the project has always enforced:
|
|
11
|
+
|
|
12
|
+
- required status checks (`ci required checks passed`, `security required checks
|
|
13
|
+
passed`, `conventional PR title`, `lint`) with strict / up-to-date branches,
|
|
14
|
+
- linear history, conversation resolution, a pull request required (0 approvals —
|
|
15
|
+
solo maintainer), and blocked deletions / force-pushes,
|
|
16
|
+
- `enforcement: active` with an empty `bypass_actors` list — i.e. admins are
|
|
17
|
+
enforced too (the old `enforce_admins: true`).
|
|
18
|
+
|
|
19
|
+
## Tag protection + immutable releases
|
|
20
|
+
|
|
21
|
+
`tags.json` is a second ruleset (`target: tag`) over `refs/tags/v*` that blocks
|
|
22
|
+
**deletion** and **non-fast-forward** (moving) of release tags, with no bypass —
|
|
23
|
+
so a published version tag can't be repointed or removed. Tag *creation* is not
|
|
24
|
+
blocked, so release-please can still cut new `vX.Y.Z` tags.
|
|
25
|
+
|
|
26
|
+
This pairs with **immutable releases** (enabled on the repo via
|
|
27
|
+
`PUT /repos/{owner}/{repo}/immutable-releases`): once a release is published its
|
|
28
|
+
tag is locked to its commit and its assets can't be changed, and a release
|
|
29
|
+
attestation is generated. Immutability applies to *future* releases only; the
|
|
30
|
+
release **body/notes remain editable**, so the post-publish
|
|
31
|
+
`gh release edit --notes-file` step (when needed) still works.
|
|
32
|
+
|
|
33
|
+
## Applying
|
|
34
|
+
|
|
35
|
+
The rulesets are currently applied/maintained manually via the API. Each file
|
|
36
|
+
maps to one ruleset: `main.json` → ruleset **`main`** (branch), `tags.json` →
|
|
37
|
+
ruleset **`protect-version-tags`** (tag).
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
# create (first time)
|
|
41
|
+
gh api -X POST repos/<owner>/<repo>/rulesets --input .github/rulesets/main.json
|
|
42
|
+
gh api -X POST repos/<owner>/<repo>/rulesets --input .github/rulesets/tags.json
|
|
43
|
+
|
|
44
|
+
# update an existing ruleset (look up its id by name first)
|
|
45
|
+
id=$(gh api repos/<owner>/<repo>/rulesets --jq '.[]|select(.name=="main")|.id')
|
|
46
|
+
gh api -X PUT repos/<owner>/<repo>/rulesets/"$id" --input .github/rulesets/main.json
|
|
47
|
+
id=$(gh api repos/<owner>/<repo>/rulesets --jq '.[]|select(.name=="protect-version-tags")|.id')
|
|
48
|
+
gh api -X PUT repos/<owner>/<repo>/rulesets/"$id" --input .github/rulesets/tags.json
|
|
49
|
+
|
|
50
|
+
# verify: effective branch rules, every ruleset, and immutable releases
|
|
51
|
+
gh api repos/<owner>/<repo>/rules/branches/main
|
|
52
|
+
gh api repos/<owner>/<repo>/rulesets --jq '.[]|{id,name,target,enforcement}'
|
|
53
|
+
gh api repos/<owner>/<repo>/immutable-releases # expect {"enabled": true, ...}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Immutable releases is a repo setting, not a ruleset file: enable with
|
|
57
|
+
`gh api -X PUT repos/<owner>/<repo>/immutable-releases` (disable with `-X DELETE`).
|
|
58
|
+
|
|
59
|
+
A small GitHub Action to reconcile these files (plus repo settings and labels)
|
|
60
|
+
automatically — applying on merge and re-applying on a schedule to revert
|
|
61
|
+
out-of-band drift — is planned. Until then, edit the JSON and re-apply by hand.
|
|
62
|
+
|
|
63
|
+
[app]: https://github.com/repository-settings/app
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "main",
|
|
3
|
+
"target": "branch",
|
|
4
|
+
"enforcement": "active",
|
|
5
|
+
"bypass_actors": [],
|
|
6
|
+
"conditions": {
|
|
7
|
+
"ref_name": {
|
|
8
|
+
"include": ["~DEFAULT_BRANCH"],
|
|
9
|
+
"exclude": []
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"rules": [
|
|
13
|
+
{ "type": "deletion" },
|
|
14
|
+
{ "type": "non_fast_forward" },
|
|
15
|
+
{ "type": "required_linear_history" },
|
|
16
|
+
{
|
|
17
|
+
"type": "pull_request",
|
|
18
|
+
"parameters": {
|
|
19
|
+
"required_approving_review_count": 0,
|
|
20
|
+
"dismiss_stale_reviews_on_push": true,
|
|
21
|
+
"require_code_owner_review": false,
|
|
22
|
+
"require_last_push_approval": false,
|
|
23
|
+
"required_review_thread_resolution": true,
|
|
24
|
+
"allowed_merge_methods": ["squash"]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "required_status_checks",
|
|
29
|
+
"parameters": {
|
|
30
|
+
"strict_required_status_checks_policy": true,
|
|
31
|
+
"do_not_enforce_on_create": false,
|
|
32
|
+
"required_status_checks": [
|
|
33
|
+
{ "context": "ci required checks passed", "integration_id": 15368 },
|
|
34
|
+
{ "context": "security required checks passed", "integration_id": 15368 },
|
|
35
|
+
{ "context": "conventional PR title", "integration_id": 15368 },
|
|
36
|
+
{ "context": "lint", "integration_id": 15368 }
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"type": "code_scanning",
|
|
42
|
+
"parameters": {
|
|
43
|
+
"code_scanning_tools": [
|
|
44
|
+
{
|
|
45
|
+
"tool": "CodeQL",
|
|
46
|
+
"security_alerts_threshold": "high_or_higher",
|
|
47
|
+
"alerts_threshold": "errors"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "protect-version-tags",
|
|
3
|
+
"target": "tag",
|
|
4
|
+
"enforcement": "active",
|
|
5
|
+
"bypass_actors": [],
|
|
6
|
+
"conditions": {
|
|
7
|
+
"ref_name": {
|
|
8
|
+
"include": ["refs/tags/v*"],
|
|
9
|
+
"exclude": []
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"rules": [
|
|
13
|
+
{ "type": "deletion" },
|
|
14
|
+
{ "type": "non_fast_forward" }
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -15,7 +15,8 @@ concurrency:
|
|
|
15
15
|
jobs:
|
|
16
16
|
lint:
|
|
17
17
|
# This job name is a REQUIRED status check — it must match the context list
|
|
18
|
-
# in .github/
|
|
18
|
+
# in the `main` ruleset (.github/rulesets/main.json) exactly (renaming means
|
|
19
|
+
# updating that ruleset too).
|
|
19
20
|
# Runs ruff (check + format), pyright, and the Markdown + YAML doc-lint
|
|
20
21
|
# (scripts/lint-docs.sh).
|
|
21
22
|
name: lint
|
|
@@ -29,5 +29,5 @@ rules:
|
|
|
29
29
|
level: warning
|
|
30
30
|
# Workflow/config files routinely omit the `---` start marker.
|
|
31
31
|
document-start: disable
|
|
32
|
-
#
|
|
32
|
+
# Some config files align comments under keys; don't fight that.
|
|
33
33
|
comments-indentation: disable
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.0](https://github.com/schubydoo/clauster/compare/v0.2.2...v0.3.0) (2026-06-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **docker:** add a Docker Compose quickstart ([#97](https://github.com/schubydoo/clauster/issues/97)) ([e6c914d](https://github.com/schubydoo/clauster/commit/e6c914d22e648ede2dd3c0285a717fdae5f1bef2))
|
|
9
|
+
* **doctor:** check that the claude CLI is logged in ([#84](https://github.com/schubydoo/clauster/issues/84)) ([f902f23](https://github.com/schubydoo/clauster/commit/f902f23af6876f1cc95e450c0d4f1447c5e71cfe))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* **runner:** serialize concurrent spawns of the same project ([#91](https://github.com/schubydoo/clauster/issues/91)) ([2dc8eb0](https://github.com/schubydoo/clauster/commit/2dc8eb044aaed3e735627f2feedbce8281a6b298))
|
|
15
|
+
* **runner:** stop wiping persisted metadata for untracked projects ([#92](https://github.com/schubydoo/clauster/issues/92)) ([cca1c69](https://github.com/schubydoo/clauster/commit/cca1c69ec29a48c2d034d64cdf5a23e4dca1383a))
|
|
16
|
+
* show Restart for stopped pty bridges so true-resume is reachable ([#99](https://github.com/schubydoo/clauster/issues/99)) ([5ea38aa](https://github.com/schubydoo/clauster/commit/5ea38aaa0b2ed92039681be4babe32c7ba9ad465))
|
|
17
|
+
|
|
3
18
|
## [0.2.2](https://github.com/schubydoo/clauster/compare/v0.2.1...v0.2.2) (2026-06-03)
|
|
4
19
|
|
|
5
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clauster
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Self-hosted web UI for spawning and managing Claude Code remote-control bridges on a remote host.
|
|
5
5
|
Project-URL: Homepage, https://github.com/schubydoo/clauster
|
|
6
6
|
Project-URL: Repository, https://github.com/schubydoo/clauster
|
|
@@ -59,7 +59,8 @@ Description-Content-Type: text/markdown
|
|
|
59
59
|
</p>
|
|
60
60
|
|
|
61
61
|
<p align="center">
|
|
62
|
-
<img alt="
|
|
62
|
+
<a href="https://pypi.org/project/clauster/"><img alt="PyPI" src="https://img.shields.io/pypi/v/clauster?logo=pypi&logoColor=white"></a>
|
|
63
|
+
<a href="https://pypi.org/project/clauster/"><img alt="Python versions" src="https://img.shields.io/pypi/pyversions/clauster"></a>
|
|
63
64
|
<a href="https://github.com/schubydoo/clauster/blob/main/LICENSE"><img alt="License: Apache-2.0" src="https://img.shields.io/badge/license-Apache--2.0-blue.svg"></a>
|
|
64
65
|
<a href="https://github.com/schubydoo/clauster/pkgs/container/clauster"><img alt="GHCR" src="https://img.shields.io/badge/ghcr.io-clauster-2496ED?logo=docker&logoColor=white"></a>
|
|
65
66
|
<a href="https://github.com/astral-sh/ruff"><img alt="Ruff" src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json"></a>
|
|
@@ -121,7 +122,7 @@ it in [`clauster.yml.example`](https://github.com/schubydoo/clauster/blob/main/c
|
|
|
121
122
|
permission mode per launch. `bypassPermissions` is double-gated: a per-project
|
|
122
123
|
config ceiling (`projects.<name>.allow_bypass_permissions`) **and** a
|
|
123
124
|
type-the-project-name confirm in the UI.
|
|
124
|
-
- **Open in Claude** — a deep link to the primary session plus a scannable QR code
|
|
125
|
+
- **Open session in Claude** — a deep link to the primary session plus a scannable QR code
|
|
125
126
|
that opens it in the Claude app (claude.ai/code or mobile), attached to the
|
|
126
127
|
running bridge.
|
|
127
128
|
- **External session surfacing** — sessions you started from a terminal or Desktop
|
|
@@ -183,6 +184,33 @@ uv run clauster
|
|
|
183
184
|
Then open <http://127.0.0.1:7621>. `claude` must be on your `PATH` (Clauster spawns
|
|
184
185
|
it; it isn't vendored).
|
|
185
186
|
|
|
187
|
+
## First bridge in 60 seconds
|
|
188
|
+
|
|
189
|
+
With the server running (above) and `claude` on your `PATH`, spawning your first
|
|
190
|
+
bridge is a handful of clicks — no terminal needed once it's started:
|
|
191
|
+
|
|
192
|
+
1. **Point Clauster at your code.** Set `projects_root` in `clauster.yml` to a
|
|
193
|
+
directory whose subfolders are projects (e.g. `~/code`); each child directory
|
|
194
|
+
becomes a card.
|
|
195
|
+
2. **Sanity-check the host (optional).** `clauster doctor` confirms `claude` is found
|
|
196
|
+
and new enough and that `projects_root` / the state dir are usable — fix any ✗
|
|
197
|
+
before spawning.
|
|
198
|
+
3. **Open the dashboard** at <http://127.0.0.1:7621>. You'll see one card per project.
|
|
199
|
+
4. **Start a bridge.** On a project's card, click **Start**. Clauster launches
|
|
200
|
+
`claude remote-control` in that directory and the card flips to *Running* with a
|
|
201
|
+
live status badge. (Pick a spawn / permission mode first if you like — the
|
|
202
|
+
defaults are safe.)
|
|
203
|
+
5. **Attach from anywhere.** Use the card's **Open session in Claude** link — or scan its
|
|
204
|
+
**QR code** — to pick the bridge up in `claude.ai/code` or the Claude mobile app.
|
|
205
|
+
No SSH session.
|
|
206
|
+
6. **Stop or restart.** **Stop** signals the bridge; **Restart** relaunches it (with
|
|
207
|
+
`claude.resume_recap` or `resume_mode: pty` it can carry the prior conversation
|
|
208
|
+
forward — see [Opt-in extras](#opt-in-extras)).
|
|
209
|
+
|
|
210
|
+
> Exposing this beyond loopback (e.g. on your LAN)? Read
|
|
211
|
+
> [Auth & networking](#auth--networking) first — a non-loopback bind requires
|
|
212
|
+
> authentication.
|
|
213
|
+
|
|
186
214
|
## Docker
|
|
187
215
|
|
|
188
216
|
Multi-arch images (`linux/amd64`, `linux/arm64`) are published to GHCR on each release.
|
|
@@ -223,6 +251,19 @@ docker run -d --name clauster \
|
|
|
223
251
|
- Logs are JSON by default (`CLAUSTER_LOG_FORMAT`); health is at `/healthz`. Images
|
|
224
252
|
are cosign-signed with build provenance + SBOM attestations.
|
|
225
253
|
|
|
254
|
+
### Docker Compose
|
|
255
|
+
|
|
256
|
+
A ready-to-edit [`compose.yaml`](https://github.com/schubydoo/clauster/blob/main/compose.yaml) is included:
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
# 1. generate a password hash (runs inside the image)
|
|
260
|
+
docker compose run --rm clauster clauster hash-password
|
|
261
|
+
# 2. export it single-quoted, then edit the projects/claude volumes in compose.yaml
|
|
262
|
+
export CLAUSTER_AUTH_PASSWORD_HASH='$argon2id$v=19$...'
|
|
263
|
+
# 3. start (the image's HEALTHCHECK is inherited)
|
|
264
|
+
docker compose up -d
|
|
265
|
+
```
|
|
266
|
+
|
|
226
267
|
## Auth & networking
|
|
227
268
|
|
|
228
269
|
Loopback (`127.0.0.1`) needs no auth. Binding to a non-loopback address is refused
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
19
|
-
<img alt="
|
|
19
|
+
<a href="https://pypi.org/project/clauster/"><img alt="PyPI" src="https://img.shields.io/pypi/v/clauster?logo=pypi&logoColor=white"></a>
|
|
20
|
+
<a href="https://pypi.org/project/clauster/"><img alt="Python versions" src="https://img.shields.io/pypi/pyversions/clauster"></a>
|
|
20
21
|
<a href="https://github.com/schubydoo/clauster/blob/main/LICENSE"><img alt="License: Apache-2.0" src="https://img.shields.io/badge/license-Apache--2.0-blue.svg"></a>
|
|
21
22
|
<a href="https://github.com/schubydoo/clauster/pkgs/container/clauster"><img alt="GHCR" src="https://img.shields.io/badge/ghcr.io-clauster-2496ED?logo=docker&logoColor=white"></a>
|
|
22
23
|
<a href="https://github.com/astral-sh/ruff"><img alt="Ruff" src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json"></a>
|
|
@@ -78,7 +79,7 @@ it in [`clauster.yml.example`](https://github.com/schubydoo/clauster/blob/main/c
|
|
|
78
79
|
permission mode per launch. `bypassPermissions` is double-gated: a per-project
|
|
79
80
|
config ceiling (`projects.<name>.allow_bypass_permissions`) **and** a
|
|
80
81
|
type-the-project-name confirm in the UI.
|
|
81
|
-
- **Open in Claude** — a deep link to the primary session plus a scannable QR code
|
|
82
|
+
- **Open session in Claude** — a deep link to the primary session plus a scannable QR code
|
|
82
83
|
that opens it in the Claude app (claude.ai/code or mobile), attached to the
|
|
83
84
|
running bridge.
|
|
84
85
|
- **External session surfacing** — sessions you started from a terminal or Desktop
|
|
@@ -140,6 +141,33 @@ uv run clauster
|
|
|
140
141
|
Then open <http://127.0.0.1:7621>. `claude` must be on your `PATH` (Clauster spawns
|
|
141
142
|
it; it isn't vendored).
|
|
142
143
|
|
|
144
|
+
## First bridge in 60 seconds
|
|
145
|
+
|
|
146
|
+
With the server running (above) and `claude` on your `PATH`, spawning your first
|
|
147
|
+
bridge is a handful of clicks — no terminal needed once it's started:
|
|
148
|
+
|
|
149
|
+
1. **Point Clauster at your code.** Set `projects_root` in `clauster.yml` to a
|
|
150
|
+
directory whose subfolders are projects (e.g. `~/code`); each child directory
|
|
151
|
+
becomes a card.
|
|
152
|
+
2. **Sanity-check the host (optional).** `clauster doctor` confirms `claude` is found
|
|
153
|
+
and new enough and that `projects_root` / the state dir are usable — fix any ✗
|
|
154
|
+
before spawning.
|
|
155
|
+
3. **Open the dashboard** at <http://127.0.0.1:7621>. You'll see one card per project.
|
|
156
|
+
4. **Start a bridge.** On a project's card, click **Start**. Clauster launches
|
|
157
|
+
`claude remote-control` in that directory and the card flips to *Running* with a
|
|
158
|
+
live status badge. (Pick a spawn / permission mode first if you like — the
|
|
159
|
+
defaults are safe.)
|
|
160
|
+
5. **Attach from anywhere.** Use the card's **Open session in Claude** link — or scan its
|
|
161
|
+
**QR code** — to pick the bridge up in `claude.ai/code` or the Claude mobile app.
|
|
162
|
+
No SSH session.
|
|
163
|
+
6. **Stop or restart.** **Stop** signals the bridge; **Restart** relaunches it (with
|
|
164
|
+
`claude.resume_recap` or `resume_mode: pty` it can carry the prior conversation
|
|
165
|
+
forward — see [Opt-in extras](#opt-in-extras)).
|
|
166
|
+
|
|
167
|
+
> Exposing this beyond loopback (e.g. on your LAN)? Read
|
|
168
|
+
> [Auth & networking](#auth--networking) first — a non-loopback bind requires
|
|
169
|
+
> authentication.
|
|
170
|
+
|
|
143
171
|
## Docker
|
|
144
172
|
|
|
145
173
|
Multi-arch images (`linux/amd64`, `linux/arm64`) are published to GHCR on each release.
|
|
@@ -180,6 +208,19 @@ docker run -d --name clauster \
|
|
|
180
208
|
- Logs are JSON by default (`CLAUSTER_LOG_FORMAT`); health is at `/healthz`. Images
|
|
181
209
|
are cosign-signed with build provenance + SBOM attestations.
|
|
182
210
|
|
|
211
|
+
### Docker Compose
|
|
212
|
+
|
|
213
|
+
A ready-to-edit [`compose.yaml`](https://github.com/schubydoo/clauster/blob/main/compose.yaml) is included:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
# 1. generate a password hash (runs inside the image)
|
|
217
|
+
docker compose run --rm clauster clauster hash-password
|
|
218
|
+
# 2. export it single-quoted, then edit the projects/claude volumes in compose.yaml
|
|
219
|
+
export CLAUSTER_AUTH_PASSWORD_HASH='$argon2id$v=19$...'
|
|
220
|
+
# 3. start (the image's HEALTHCHECK is inherited)
|
|
221
|
+
docker compose up -d
|
|
222
|
+
```
|
|
223
|
+
|
|
183
224
|
## Auth & networking
|
|
184
225
|
|
|
185
226
|
Loopback (`127.0.0.1`) needs no auth. Binding to a non-loopback address is refused
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Clauster — Docker Compose quickstart. See the README "Docker" section for the full rundown.
|
|
2
|
+
#
|
|
3
|
+
# Clauster binds 0.0.0.0 inside the container, so it REQUIRES enforced auth to start.
|
|
4
|
+
#
|
|
5
|
+
# 1. Generate a password hash (runs inside the image — nothing needed on the host):
|
|
6
|
+
# docker compose run --rm clauster clauster hash-password
|
|
7
|
+
# 2. Provide the printed `$argon2id$…` hash. Easiest + safest is to export it
|
|
8
|
+
# single-quoted (single quotes stop your shell expanding the `$`):
|
|
9
|
+
# export CLAUSTER_AUTH_PASSWORD_HASH='$argon2id$v=19$...'
|
|
10
|
+
# (Or put it in a .env file beside this one — but then double every `$` to `$$`
|
|
11
|
+
# so Compose doesn't try to interpolate it.)
|
|
12
|
+
# 3. Point the `projects` volume at your projects_root, and mount the `claude` CLI +
|
|
13
|
+
# credentials (Clauster spawns `claude remote-control`; the CLI is NOT in the image).
|
|
14
|
+
# 4. docker compose up -d
|
|
15
|
+
|
|
16
|
+
services:
|
|
17
|
+
clauster:
|
|
18
|
+
image: ghcr.io/schubydoo/clauster:latest
|
|
19
|
+
container_name: clauster
|
|
20
|
+
restart: unless-stopped
|
|
21
|
+
ports:
|
|
22
|
+
- "7621:7621"
|
|
23
|
+
environment:
|
|
24
|
+
# Non-loopback bind => enforced auth is mandatory (the container exits otherwise).
|
|
25
|
+
CLAUSTER_AUTH_ENABLED: "true"
|
|
26
|
+
CLAUSTER_AUTH_PASSWORD_REQUIRED: "true"
|
|
27
|
+
CLAUSTER_AUTH_PASSWORD_HASH: ${CLAUSTER_AUTH_PASSWORD_HASH:?run clauster hash-password and export it (see header)}
|
|
28
|
+
# Remap the runtime user to own the bind-mounts (match your host UID/GID).
|
|
29
|
+
PUID: "1000"
|
|
30
|
+
PGID: "1000"
|
|
31
|
+
volumes:
|
|
32
|
+
- ./config:/config # clauster.yml + state_dir
|
|
33
|
+
- ./projects:/projects # the projects_root to manage (point at your repos)
|
|
34
|
+
# `claude` is NOT baked into the image. Mount it onto PATH + mount the runtime
|
|
35
|
+
# user's ~/.claude credentials (or build a derived image that installs claude):
|
|
36
|
+
# - /usr/local/bin/claude:/usr/local/bin/claude:ro
|
|
37
|
+
# - ~/.claude:/config/.claude
|
|
38
|
+
# The image already defines a HEALTHCHECK against /healthz — Compose inherits it.
|
|
@@ -9,12 +9,16 @@
|
|
|
9
9
|
"timezone": "Etc/UTC",
|
|
10
10
|
"schedule": ["before 7am on monday"],
|
|
11
11
|
"labels": ["dependencies"],
|
|
12
|
+
"description": "Auto-merge uses GitHub native auto-merge + squash (a real PR satisfying the main ruleset), NOT branch automerge — the ruleset requires a PR, so branch automerge would be blocked.",
|
|
13
|
+
"platformAutomerge": true,
|
|
14
|
+
"automergeStrategy": "squash",
|
|
12
15
|
"vulnerabilityAlerts": {
|
|
13
16
|
"enabled": true,
|
|
14
17
|
"labels": ["security"]
|
|
15
18
|
},
|
|
16
19
|
"lockFileMaintenance": {
|
|
17
20
|
"enabled": true,
|
|
21
|
+
"automerge": true,
|
|
18
22
|
"schedule": ["before 7am on monday"]
|
|
19
23
|
},
|
|
20
24
|
"ignorePaths": [
|
|
@@ -47,11 +51,10 @@
|
|
|
47
51
|
"labels": ["vendored-assets"]
|
|
48
52
|
},
|
|
49
53
|
{
|
|
50
|
-
"description": "Auto-merge patch updates of dev tooling.",
|
|
54
|
+
"description": "Auto-merge patch + minor updates of dev/test tooling once CI passes (a failing check blocks the merge).",
|
|
51
55
|
"matchPackageNames": ["ruff", "pyright", "pytest", "pytest-cov", "pytest-asyncio"],
|
|
52
|
-
"matchUpdateTypes": ["patch"],
|
|
53
|
-
"automerge": true
|
|
54
|
-
"automergeType": "branch"
|
|
56
|
+
"matchUpdateTypes": ["patch", "minor"],
|
|
57
|
+
"automerge": true
|
|
55
58
|
},
|
|
56
59
|
{
|
|
57
60
|
"description": "Group all pytest-related updates.",
|
|
@@ -64,11 +67,18 @@
|
|
|
64
67
|
"groupName": "ruff"
|
|
65
68
|
},
|
|
66
69
|
{
|
|
67
|
-
"description": "Roll
|
|
70
|
+
"description": "Roll non-major GitHub Actions version updates into one weekly PR (reviewed).",
|
|
68
71
|
"matchManagers": ["github-actions"],
|
|
69
|
-
"matchUpdateTypes": ["minor", "patch"
|
|
72
|
+
"matchUpdateTypes": ["minor", "patch"],
|
|
70
73
|
"groupName": "github-actions (non-major)"
|
|
71
74
|
},
|
|
75
|
+
{
|
|
76
|
+
"description": "Auto-merge GitHub Actions digest re-pins (same version, new SHA) once CI passes.",
|
|
77
|
+
"matchManagers": ["github-actions"],
|
|
78
|
+
"matchUpdateTypes": ["digest"],
|
|
79
|
+
"groupName": "github-actions digests",
|
|
80
|
+
"automerge": true
|
|
81
|
+
},
|
|
72
82
|
{
|
|
73
83
|
"description": "Group security-tooling actions — same security.yml scanners, useful to review together.",
|
|
74
84
|
"matchManagers": ["github-actions"],
|
|
@@ -10,7 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
import ipaddress
|
|
11
11
|
import os
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from typing import
|
|
13
|
+
from typing import Literal
|
|
14
14
|
|
|
15
15
|
import yaml
|
|
16
16
|
from pydantic import BaseModel, Field, PrivateAttr, field_validator, model_validator
|
|
@@ -255,9 +255,6 @@ class ClausterConfig(BaseModel):
|
|
|
255
255
|
return self
|
|
256
256
|
|
|
257
257
|
|
|
258
|
-
ConfigPath = Annotated[Path, "resolved path the config was loaded from, or None"]
|
|
259
|
-
|
|
260
|
-
|
|
261
258
|
def _candidate_paths(explicit: Path | None) -> list[Path]:
|
|
262
259
|
if explicit is not None:
|
|
263
260
|
return [explicit]
|