feat: dev channel builds with incremental pre-releases between stable releases#715
feat: dev channel builds with incremental pre-releases between stable releases#715
Conversation
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.OpenSSF Scorecard
Scanned Files
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
🧰 Additional context used📓 Path-based instructions (1)cli/**/*.go📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (2)📓 Common learnings📚 Learning: 2026-03-15T21:32:02.880ZApplied to files:
🧬 Code graph analysis (1)cli/internal/selfupdate/updater.go (1)
🔇 Additional comments (8)
WalkthroughAdds a GitHub Actions workflow Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new 'dev' update channel for the synthorg CLI, enabling users to access pre-release builds with the latest features and fixes. It automates the creation and management of these dev releases, integrating them into the existing Docker and CLI workflows. The changes also include CLI configuration updates and version comparison logic to handle dev releases correctly. Highlights
Ignored Files
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/dev-release.yml:
- Around line 114-131: If the tag creation (gh api creating refs/tags/$DEV_TAG)
succeeds but gh release create "$DEV_TAG" fails, ensure you remove the orphaned
tag on failure: run a cleanup step that deletes refs/tags/$DEV_TAG via the
GitHub API (the same gh api endpoint but with DELETE) when gh release create
returns non-zero (implement with a conditional check or a trap so it runs on
error). Update the workflow around the gh api
"repos/$GITHUB_REPOSITORY/git/refs" and gh release create "$DEV_TAG" steps to
perform the delete cleanup (or roll both actions into an atomic procedure using
a trap) so dangling tags are removed on partial failure.
In `@cli/internal/config/state.go`:
- Around line 165-167: In validate(), add a check for the LogLevel field similar
to the Channel check: if s.LogLevel != "" && !IsValidLogLevel(s.LogLevel) then
return a formatted error (e.g., "invalid log level %q: must be one of %s") using
sortedKeys(validLogLevels); target the validate() method and reference
s.LogLevel, IsValidLogLevel, and validLogLevels to locate and implement the
guard.
- Around line 106-123: The validation map validLogLevels is using "warning" but
the rest of the code (including generate.go's allowedLogLevels and tests) expect
"warn", causing validation mismatch; update the validLogLevels declaration to
use "warn" instead of "warning" so IsValidLogLevel and LogLevelNames align with
generate.go and the rest of the system (leave sortedKeys and related functions
unchanged).
In `@cli/internal/selfupdate/updater.go`:
- Around line 236-249: The splitDev function currently swallows malformed ".dev"
suffixes (e.g., "v0.4.7.dev" or "v0.4.7.devABC") by returning -1 as if there is
no dev tag; change splitDev to surface that parsing failure by returning an
additional error (signature splitDev(v string) (devNum int, base string, err
error)) or at minimum emit a warning via the existing logger when
strconv.Atoi(numStr) fails or when numStr is empty. Update callers to handle the
returned error (or ignore after logging) and ensure the function still returns
base correctly on success; reference splitDev, numStr and the strconv.Atoi call
when making the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: de11c498-55c7-4fad-8623-25c6e0915919
📒 Files selected for processing (11)
.github/workflows/dev-release.yml.github/workflows/docker.yml.github/workflows/finalize-release.ymlCLAUDE.mdREADME.mdcli/cmd/config.gocli/cmd/status.gocli/cmd/update.gocli/internal/config/state.gocli/internal/selfupdate/updater.gocli/internal/selfupdate/updater_version_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: CLI Test (windows-latest)
- GitHub Check: CLI Test (macos-latest)
- GitHub Check: Build Sandbox
- GitHub Check: Build Web
- GitHub Check: Build Backend
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
cli/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Use Cobra framework for CLI commands and charmbracelet libraries (huh, lipgloss) for interactive UI
Files:
cli/cmd/status.gocli/cmd/update.gocli/internal/selfupdate/updater_version_test.gocli/cmd/config.gocli/internal/config/state.gocli/internal/selfupdate/updater.go
cli/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Use native
testing.Ffuzz functions for Go fuzzing (e.g.,FuzzYamlStr)
Files:
cli/internal/selfupdate/updater_version_test.go
🧠 Learnings (30)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile.sandbox : Docker sandbox: `synthorg-sandbox` — Python 3.14 + Node.js + git, non-root (UID 10001), agent code execution sandbox
Applied to files:
README.mdCLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
README.mdCLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Applied to files:
cli/cmd/status.gocli/cmd/update.goCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).
Applied to files:
cli/cmd/status.goCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Applied to files:
CLAUDE.md.github/workflows/docker.yml
📚 Learning: 2026-03-15T16:38:08.735Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:38:08.735Z
Learning: Applies to docker/** : Docker build context: single root .dockerignore (both images build with context: .). Tags: CI tags images with version from pyproject.toml ([tool.commitizen].version), semver, and SHA.
Applied to files:
CLAUDE.md.github/workflows/docker.yml
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Applies to docker/Dockerfile* : All Docker images must use Chainguard distroless (backend), nginx-unprivileged (web), or Python + Node.js (sandbox) with non-root users
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile : Docker: 3-stage build (builder → setup → distroless runtime) for backend, Chainguard Python, non-root (UID 65532), CIS-hardened
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Sign container images with cosign and generate SLSA L3 provenance in Docker build workflow
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to docker/Dockerfile.web : `nginxinc/nginx-unprivileged` base with non-root user (UID 101), Vue 3 SPA (PrimeVue + Tailwind CSS), SPA routing, API/WebSocket proxy to backend
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Applies to cli/**/*.go : Use Cobra framework for CLI commands and charmbracelet libraries (huh, lipgloss) for interactive UI
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T20:45:14.430Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T20:45:14.430Z
Learning: Shell commands: for Go CLI work, cd cli is an exception because Go tooling requires working directory to be the module root. Go commands require `cd cli` for other work, never use `cd`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Run Go commands from `cli/` directory as the working directory since Go module is in `cli/` (exception to no-cd rule)
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Lint Go code with `golangci-lint` and `go vet`. Run tests with `-race` flag to detect race conditions.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Add `Release-As: <version>` trailer as the final paragraph of PR body (separated by blank line) to override version bumping in Release Please
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Version locations: `pyproject.toml` (`[tool.commitizen].version`) and `src/synthorg/__init__.py` (`__version__`)
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint (Dockerfile linting).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Dependabot: auto-updates Docker image digests and versions daily.
Applied to files:
.github/workflows/docker.yml
🧬 Code graph analysis (4)
cli/cmd/update.go (3)
cli/internal/config/state.go (1)
Load(64-102)web/src/api/types.ts (1)
Channel(591-595)cli/internal/selfupdate/updater.go (1)
CheckForChannel(70-75)
cli/cmd/config.go (1)
cli/internal/config/state.go (6)
Load(64-102)IsValidChannel(110-112)ChannelNames(115-115)IsValidLogLevel(118-120)LogLevelNames(123-123)Save(218-232)
cli/internal/config/state.go (1)
web/src/api/types.ts (1)
Channel(591-595)
cli/internal/selfupdate/updater.go (1)
cli/internal/version/version.go (1)
Version(9-9)
🔇 Additional comments (29)
cli/cmd/status.go (1)
76-81: LGTM!The channel display integrates cleanly with existing version info output, using the
DisplayChannel()helper for consistent formatting.README.md (1)
105-105: LGTM!Clear documentation of the new dev channel opt-in command with a concise explanatory comment.
.github/workflows/finalize-release.yml (1)
24-31: LGTM!The guard correctly excludes dev pre-releases from finalization. Dev pre-releases are created as non-draft by
dev-release.ymland don't require this workflow's verification assembly step.cli/cmd/update.go (1)
112-124: LGTM!The channel-aware update logic correctly:
- Defaults to
"stable"when config load fails or channel is empty- Provides user feedback when checking the dev channel
- Routes through
CheckForChannelwhich handles the stable/dev branchingCLAUDE.md (4)
98-98: LGTM!Docker tag documentation accurately reflects the new dev version scheme and rolling
devtag.
134-134: LGTM!CLI command list updated to include the new
configcommand.
226-226: LGTM!Clear documentation of the dev channel workflow and opt-in mechanism.
245-246: LGTM!CI documentation accurately describes the new
dev-release.ymlworkflow behavior and the updatedfinalize-release.ymlguard..github/workflows/docker.yml (3)
93-94: LGTM!The tagging logic correctly:
- Excludes
major.minorsemver tags for dev builds (prevents dev releases from overwriting stable minor tags)- Adds a rolling
devtag for dev pre-releases
282-283: LGTM!Consistent tagging logic applied to the web image.
467-468: LGTM!Consistent tagging logic applied to the sandbox image.
cli/internal/selfupdate/updater_version_test.go (1)
43-140: LGTM!Comprehensive table-driven tests for the dev version comparison logic:
TestSplitDev: covers numeric dev suffixes, empty/invalid suffixes, and stable versionsTestCompareWithDev: validates ordering rules between stable and dev releasesTestIsDevUpdateAvailable: confirms update availability semantics (stable beats same-base dev, higher base dev is an update, etc.)cli/cmd/config.go (3)
32-47: LGTM!The
config setcommand is well-structured with clear documentation of supported keys and their valid values.
77-77: LGTM!Channel display added consistently with other config fields.
93-123: LGTM!The
runConfigSethandler correctly:
- Validates keys against an explicit allowlist with helpful error messages
- Uses
config.IsValidChannel/IsValidLogLevelfor value validation- Includes valid options in error messages via
ChannelNames()/LogLevelNames()- Persists changes atomically via
config.Savecli/internal/config/state.go (3)
19-19: LGTM!The new
Channelfield is correctly added to theStatestruct with appropriate JSON serialization tag.
39-39: LGTM!Defaulting to
"stable"aligns with the design where users must explicitly opt-in to the dev channel.
49-55: LGTM!
DisplayChannel()correctly provides backward compatibility by defaulting empty channels to"stable", which handles existing config files gracefully during migration..github/workflows/dev-release.yml (6)
12-16: LGTM!Empty top-level permissions with job-scoped
contents: writefollows least-privilege principle. The concurrency group withcancel-in-progress: truecorrectly prevents race conditions on rapid pushes to main.
32-35: LGTM!
fetch-depth: 0is required forgit describeandgit rev-listto work correctly.persist-credentials: falseis a good security practice.
37-48: LGTM!Correctly skips dev release creation when a stable tag already points at HEAD, preventing duplicate releases.
91-102: LGTM!Idempotency check prevents re-creating existing dev tags on workflow re-runs.
140-147: LGTM!The cleanup logic correctly implements the "keep last 5 dev pre-releases" policy from the PR objectives. Using
--cleanup-tagensures both the release and its associated tag are removed.
55-61: No action needed. The--matchpattern correctly excludes dev tags.The glob pattern
v[0-9]*.[0-9]*.[0-9]*matches three version components separated by literal dots, where[0-9]*restricts each component to digits only. This correctly excludes tags likev0.4.7.dev1since.dev1does not match the digit-only requirement of the final[0-9]*. The code works as intended without modification.> Likely an incorrect or invalid review comment.cli/internal/selfupdate/updater.go (5)
27-33: LGTM!Constants are well-defined with clear documentation. The
devReleasesURLcorrectly usesper_page=20to fetch recent releases including pre-releases.
67-75: LGTM!Clean channel-based routing. Defaulting unknown channels to stable is safe behavior.
110-126: LGTM!The logic correctly identifies dev pre-releases (both
Prereleaseflag AND.devin tag name), distinguishing them from other pre-release types like RCs. Draft releases are properly excluded.
170-206: LGTM!Well-implemented generic HTTP helper with proper rate-limit handling, User-Agent header (per PR objectives), and response size limiting.
264-294: LGTM!Clean refactor that leverages the new generic
fetchJSONhelper while maintaining the stable update check logic.
| // splitDev splits "0.4.7.dev3" into (3, "0.4.7") or (-1, "0.4.7") if no .dev suffix. | ||
| func splitDev(v string) (devNum int, base string) { | ||
| idx := strings.Index(v, ".dev") | ||
| if idx < 0 { | ||
| return -1, v | ||
| } | ||
| base = v[:idx] | ||
| numStr := v[idx+4:] // skip ".dev" | ||
| n, err := strconv.Atoi(numStr) | ||
| if err != nil { | ||
| return -1, v | ||
| } | ||
| return release, nil | ||
| return n, base | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Silent fallback in splitDev may mask malformed dev tags.
When parsing fails (e.g., v0.4.7.dev without a number, or v0.4.7.devABC), the function silently returns -1 treating it as a non-dev version. While this is defensive, consider logging a warning or returning an error to aid debugging malformed release tags.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@cli/internal/selfupdate/updater.go` around lines 236 - 249, The splitDev
function currently swallows malformed ".dev" suffixes (e.g., "v0.4.7.dev" or
"v0.4.7.devABC") by returning -1 as if there is no dev tag; change splitDev to
surface that parsing failure by returning an additional error (signature
splitDev(v string) (devNum int, base string, err error)) or at minimum emit a
warning via the existing logger when strconv.Atoi(numStr) fails or when numStr
is empty. Update callers to handle the returned error (or ignore after logging)
and ensure the function still returns base correctly on success; reference
splitDev, numStr and the strconv.Atoi call when making the change.
There was a problem hiding this comment.
Code Review
This pull request introduces a 'dev' update channel for pre-release builds, a significant feature enhancement. The implementation is of high quality, with good refactoring (e.g., generic fetchJSON) and thorough testing. The changes are comprehensive, affecting CI/CD, Docker, and the CLI. I have a couple of suggestions to improve configuration handling robustness and maintainability.
cli/cmd/config.go
Outdated
| } | ||
| state.LogLevel = value | ||
| default: | ||
| return fmt.Errorf("unknown config key %q (supported: channel, log_level)", key) |
There was a problem hiding this comment.
The list of supported keys is hardcoded in this error message. This could become out of sync if more keys are added to the switch statement. To improve maintainability, you could refactor this to use a map of handlers for each key. This would provide a single source of truth for supported keys and their validation logic, and the error message could be generated dynamically from the map's keys.
| if s.Channel != "" && !IsValidChannel(s.Channel) { | ||
| return fmt.Errorf("invalid channel %q: must be one of %s", s.Channel, sortedKeys(validChannels)) | ||
| } |
There was a problem hiding this comment.
You've added validation for the channel field in config.Load, which is great for robustness. To be consistent, you should also validate the log_level field here. Currently, an invalid log_level in config.json would be loaded without error, whereas synthorg config set correctly validates it. Adding validation in State.validate() ensures that the configuration is always valid, regardless of how it's modified.
| if s.Channel != "" && !IsValidChannel(s.Channel) { | |
| return fmt.Errorf("invalid channel %q: must be one of %s", s.Channel, sortedKeys(validChannels)) | |
| } | |
| if s.Channel != "" && !IsValidChannel(s.Channel) { | |
| return fmt.Errorf("invalid channel %q: must be one of %s", s.Channel, sortedKeys(validChannels)) | |
| } | |
| if !IsValidLogLevel(s.LogLevel) { | |
| return fmt.Errorf("invalid log_level %q: must be one of %s", s.LogLevel, LogLevelNames()) | |
| } |
… releases
Add a dev-release workflow that creates PEP 440 dev versions (v0.4.7.dev1,
v0.4.7.dev2, etc.) on every push to main between stable releases. Dev builds
get full pipeline treatment: Docker images, CLI binaries, cosign signatures,
and SLSA provenance -- triggered by creating proper v* tags that the existing
Docker and CLI workflows already handle.
CLI changes:
- Add Channel config field ("stable" / "dev") with validation
- Add CheckDev/CheckForChannel to selfupdate with dev-aware version comparison
- Add `synthorg config set channel dev` command
- Show channel in `synthorg status` and `synthorg config show`
Workflow changes:
- New dev-release.yml: compute dev version, create tag + pre-release, cleanup
- docker.yml: add rolling `dev` tag for dev builds
- finalize-release.yml: guard against publishing dev pre-releases
Closes #713
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Pre-reviewed by 4 agents (go-reviewer, infra-reviewer, security-reviewer,
docs-consistency), 18 findings addressed:
Workflow fixes:
- Use GitHub API for tag creation instead of git push (persist-credentials: false)
- Add concurrency group to prevent race between parallel dev-release runs
- Fix expression injection: use env vars instead of inline ${{ }} in run steps
- Add explicit sort for dev release cleanup robustness
- Tighten dev tag enable expression to require refs/tags/v prefix
Go fixes:
- Add log_level validation with allowlist (was accepting arbitrary values)
- Replace duplicate fetchDevReleases/fetchRelease with generic fetchJSON[T]
- Surface compareWithDev errors instead of silently swallowing them
- Add User-Agent header to GitHub API requests
- Unexport DevReleasesURL (only used internally)
- Extract DisplayChannel() helper to deduplicate channel fallback logic
- Add rate-limit-aware error messages for 403/429 responses
Tests:
- Add table-driven tests for splitDev, compareWithDev, isDevUpdateAvailable
Docs:
- CLAUDE.md: add dev-release workflow, dev channel, config command, dev tags
- README.md: add config command to quick start
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Guard Docker app_version tag against dev builds (prevents overwriting stable image tags) - Fix git describe to exclude dev tags via grep filter (prevents broken version computation after first dev release) - Use atomic gh release create --target instead of separate tag + release API calls (prevents orphaned tags on partial failure) - Fix validLogLevels to use "warn" instead of "warning" (aligns with compose/generate.go's allowedLogLevels) - Add LogLevel validation to config validate() (catches invalid values on config load, not just config set) - Extract selectBestRelease and resolveUpdateChannel helpers (functions exceeded 50-line limit) - Make config set error message dynamic via supportedConfigKeys slice - Add error path tests for compareWithDev and isDevUpdateAvailable - Add unit tests for IsValidChannel, IsValidLogLevel, DisplayChannel - Add config set command tests (valid channel, invalid channel, unknown key) - Add integration tests for CheckDevFromURL with mocked HTTP server - Add rate-limit (403) response test for fetchJSON - Update docs: user_guide.md (config command, dev channel), operations.md (channel-aware update), tech-stack.md (dev channel mention) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
60f3eb0 to
5749d59
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@cli/internal/selfupdate/updater.go`:
- Around line 177-179: fetchJSON currently creates a new http.Client on each
call which prevents connection reuse; change it to use a shared client by either
introducing a package-level variable (e.g. var httpClient =
&http.Client{Timeout: 30 * time.Second}) or by adding an http.Client parameter
to fetchJSON so callers can pass a reused client; update references to fetchJSON
accordingly and ensure the timeout is set on the shared client or preserved by
callers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1b3c8af3-c4fc-42f0-9754-f97c1cf1c312
📒 Files selected for processing (17)
.github/workflows/dev-release.yml.github/workflows/docker.yml.github/workflows/finalize-release.ymlCLAUDE.mdREADME.mdcli/cmd/config.gocli/cmd/config_test.gocli/cmd/status.gocli/cmd/update.gocli/internal/config/state.gocli/internal/config/state_test.gocli/internal/selfupdate/updater.gocli/internal/selfupdate/updater_test.gocli/internal/selfupdate/updater_version_test.godocs/architecture/tech-stack.mddocs/design/operations.mddocs/user_guide.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: CLI Test (windows-latest)
- GitHub Check: Build Backend
- GitHub Check: Build Sandbox
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
cli/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Use Cobra framework for CLI commands and charmbracelet libraries (huh, lipgloss) for interactive UI
Files:
cli/cmd/status.gocli/cmd/update.gocli/internal/selfupdate/updater_test.gocli/cmd/config_test.gocli/internal/config/state.gocli/internal/config/state_test.gocli/internal/selfupdate/updater.gocli/internal/selfupdate/updater_version_test.gocli/cmd/config.go
cli/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Use native
testing.Ffuzz functions for Go fuzzing (e.g.,FuzzYamlStr)
Files:
cli/internal/selfupdate/updater_test.gocli/cmd/config_test.gocli/internal/config/state_test.gocli/internal/selfupdate/updater_version_test.go
🧠 Learnings (40)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile.sandbox : Docker sandbox: `synthorg-sandbox` — Python 3.14 + Node.js + git, non-root (UID 10001), agent code execution sandbox
Applied to files:
README.mddocs/user_guide.mdCLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
README.mddocs/architecture/tech-stack.mddocs/user_guide.mdCLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Applied to files:
cli/cmd/status.gocli/cmd/update.goCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).
Applied to files:
cli/cmd/status.goCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/finalize-release.yml : Finalize Release workflow: publishes draft releases created by Release Please. Triggers on workflow_run completion of Docker and CLI workflows. Verifies both workflows succeeded for the associated tag before publishing. Extracts CLI checksums, cosign verification, and container verification data from HTML comments, assembles into combined Verification section. Guards against PR-triggered runs. Handles TOCTOU races. Immutable releases enabled—once published, release assets and body cannot be modified.
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/dev-release.ymlcli/internal/selfupdate/updater.go
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Applied to files:
.github/workflows/finalize-release.ymlCLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Applied to files:
.github/workflows/finalize-release.ymldocs/architecture/tech-stack.mddocs/design/operations.mdCLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Applied to files:
docs/architecture/tech-stack.mddocs/design/operations.mdCLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/security/**/*.py : Security package (security/): SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume)
Applied to files:
docs/architecture/tech-stack.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Documentation source in `docs/` (Markdown, built with Zensical). Design spec in `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations). Architecture in `docs/architecture/` (overview, tech-stack, decision log). Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`. Reference in `docs/reference/`. REST API reference in `docs/rest-api.md`. Library reference in `docs/api/` (auto-generated from docstrings). Custom templates in `docs/overrides/`. Config in `mkdocs.yml`.
Applied to files:
docs/architecture/tech-stack.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to go.mod : Maintain Go 1.26+ requirement. Dependencies: Cobra (CLI framework), charmbracelet/huh and charmbracelet/lipgloss (UI), sigstore-go (code signing), go-containerregistry (container image verification), go-tuf (TUF client for Sigstore).
Applied to files:
docs/architecture/tech-stack.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers
Applied to files:
docs/architecture/tech-stack.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Applied to files:
docs/architecture/tech-stack.mddocs/user_guide.mdCLAUDE.md.github/workflows/docker.yml
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/security/**/*.py : Security module includes SecOps agent, rule engine (soft-allow/hard-deny), audit log, output scanner, risk classifier, autonomy levels (4 strategies), timeout policies.
Applied to files:
docs/architecture/tech-stack.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Security: SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies: disabled/weighted/per-category/milestone), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume).
Applied to files:
docs/architecture/tech-stack.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-15T16:38:08.735Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T16:38:08.735Z
Learning: Applies to docker/** : Docker build context: single root .dockerignore (both images build with context: .). Tags: CI tags images with version from pyproject.toml ([tool.commitizen].version), semver, and SHA.
Applied to files:
CLAUDE.md.github/workflows/docker.yml
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Applies to docker/Dockerfile* : All Docker images must use Chainguard distroless (backend), nginx-unprivileged (web), or Python + Node.js (sandbox) with non-root users
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docker/Dockerfile : Docker: 3-stage build (builder → setup → distroless runtime) for backend, Chainguard Python, non-root (UID 65532), CIS-hardened
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Sign container images with cosign and generate SLSA L3 provenance in Docker build workflow
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to docker/Dockerfile.web : `nginxinc/nginx-unprivileged` base with non-root user (UID 101), Vue 3 SPA (PrimeVue + Tailwind CSS), SPA routing, API/WebSocket proxy to backend
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Applies to cli/**/*.go : Use Cobra framework for CLI commands and charmbracelet libraries (huh, lipgloss) for interactive UI
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T20:45:14.430Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T20:45:14.430Z
Learning: Shell commands: for Go CLI work, cd cli is an exception because Go tooling requires working directory to be the module root. Go commands require `cd cli` for other work, never use `cd`.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Run Go commands from `cli/` directory as the working directory since Go module is in `cli/` (exception to no-cd rule)
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Lint Go code with `golangci-lint` and `go vet`. Run tests with `-race` flag to detect race conditions.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Add `Release-As: <version>` trailer as the final paragraph of PR body (separated by blank line) to override version bumping in Release Please
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-22T08:19:13.388Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-22T08:19:13.388Z
Learning: Version locations: `pyproject.toml` (`[tool.commitizen].version`) and `src/synthorg/__init__.py` (`__version__`)
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to .github/workflows/**/*.yml : Path filtering: dorny/paths-filter detects Python/dashboard/docker changes; jobs only run when their domain is affected. CLI has its own workflow (cli.yml).
Applied to files:
CLAUDE.md.github/workflows/docker.yml.github/workflows/dev-release.yml
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint (Dockerfile linting).
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Dependabot: auto-updates Docker image digests and versions daily.
Applied to files:
.github/workflows/docker.yml
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.
Applied to files:
cli/internal/config/state.go
📚 Learning: 2026-03-15T21:49:53.264Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:49:53.264Z
Learning: Fix everything valid — never skip when review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to the PR's changes). No deferring, no 'out of scope' skipping.
Applied to files:
.github/workflows/dev-release.yml
🧬 Code graph analysis (7)
cli/cmd/update.go (2)
cli/internal/selfupdate/updater.go (1)
CheckForChannel(70-75)cli/internal/config/state.go (1)
Load(64-102)
cli/internal/selfupdate/updater_test.go (1)
cli/internal/selfupdate/updater.go (2)
Asset(52-55)CheckDevFromURL(99-132)
cli/cmd/config_test.go (3)
cli/internal/config/state.go (3)
DefaultState(35-47)Save(221-235)Load(64-102)cli/internal/config/paths.go (1)
DataDir(18-31)cli/cmd/root.go (1)
Execute(101-107)
cli/internal/config/state.go (1)
web/src/api/types.ts (1)
Channel(591-595)
cli/internal/config/state_test.go (1)
cli/internal/config/state.go (4)
IsValidChannel(110-112)IsValidLogLevel(118-120)State(16-30)Load(64-102)
cli/internal/selfupdate/updater.go (1)
cli/internal/version/version.go (1)
Version(9-9)
cli/cmd/config.go (1)
cli/internal/config/state.go (6)
Load(64-102)IsValidChannel(110-112)ChannelNames(115-115)IsValidLogLevel(118-120)LogLevelNames(123-123)Save(221-235)
🔇 Additional comments (31)
README.md (1)
105-105: LGTM!The documentation update correctly introduces the
config set channel devcommand to opt in to pre-release builds, with a clear inline comment explaining its purpose.cli/cmd/status.go (1)
76-82: LGTM!The channel display is cleanly integrated into
printVersionInfo, maintaining consistency with the existingKeyValueoutput pattern. The use ofDisplayChannel()correctly handles the fallback to "stable" when the channel is unset..github/workflows/finalize-release.yml (1)
24-31: LGTM!The guard condition correctly excludes
.devtags from finalization. The combination ofstartsWith(head_branch, 'v')and!contains(head_branch, '.dev')properly distinguishes stable releases (e.g.,v0.4.7) from dev pre-releases (e.g.,v0.4.7.dev3). The added comments clearly document the rationale.docs/architecture/tech-stack.md (1)
65-65: LGTM!The tech stack documentation accurately describes the new channel selection feature alongside the existing CLI capabilities.
docs/design/operations.md (1)
1039-1048: LGTM!The documentation accurately reflects the channel-aware update behavior (
stable/dev) and the compose template refresh with diff approval. This aligns with the implementation incli/cmd/update.go.cli/cmd/update.go (2)
112-118: LGTM!The channel-aware update check provides clear user feedback distinguishing between dev and stable channel checks. The conditional messaging improves transparency about which channel is being queried.
157-165: LGTM!The
resolveUpdateChannelfunction correctly implements a fail-safe pattern: if config loading fails or the channel is empty, it defaults to"stable". This ensures update checks can proceed even with configuration issues, while users explicitly on the dev channel receive dev updates.cli/internal/selfupdate/updater_test.go (4)
826-853: LGTM!Comprehensive test for dev channel release selection. Correctly validates that
v0.4.7.dev3is selected overv0.4.6when the dev version is newer.
855-882: LGTM!Good edge case coverage: validates that stable
v0.4.7is preferred overv0.4.7.dev3when they share the same base version, ensuring users get stable releases when available.
884-899: LGTM!Validates proper error handling when all releases are drafts, ensuring the function doesn't silently succeed with no valid release.
901-914: LGTM!Good coverage for GitHub API rate limiting (HTTP 403). The assertion that the error contains "rate-limited" ensures user-friendly error messages.
docs/user_guide.md (1)
27-29: LGTM!Clear and comprehensive documentation for the dev channel feature. The user guide properly explains:
- How to opt in (
synthorg config set channel dev)- What the dev channel provides (artifacts on every push to main)
- How to switch back to stable
This gives users the information they need to make an informed choice about tracking pre-release builds.
.github/workflows/docker.yml (1)
91-95: LGTM! Dev channel tagging logic is consistent across all three images.The gating correctly:
- Excludes
.devrefs from stable version tags (raw app_version) and semver major.minor tags- Enables the rolling
devtag only for.devrefs- Preserves
type=semver,pattern={{version}}for.devrefs so the full dev version (e.g.,0.4.7.dev3) is taggedAlso applies to: 280-284, 465-469
CLAUDE.md (1)
98-98: LGTM! Documentation accurately reflects the new dev channel workflow.The updates correctly document:
- Dev tag format (
v0.4.7.dev3) and rollingdevtag- New
configcommand in CLI- Dev channel opt-in via
synthorg config set channel devdev-release.ymlbehavior and automatic cleanupfinalize-release.ymlskipping dev pre-releasesAlso applies to: 134-134, 226-226, 245-246
cli/cmd/config_test.go (1)
117-178: Good test coverage forconfig setcommand.The tests appropriately cover:
- Successful persistence and reload verification
- Invalid channel value rejection
- Unknown key rejection
One minor consideration: The tests share
rootCmdstate viaSetArgs/SetOut/SetErr. This is consistent with the existing tests in the file and appears safe since each test uses isolated temp directories.cli/internal/selfupdate/updater_version_test.go (1)
43-142: Excellent table-driven test coverage for dev version semantics.The tests comprehensively cover:
splitDev: Normal cases, edge cases (empty/non-numeric.devsuffix treated as stable)compareWithDev: Ordering rules including "stable beats same-base dev", "higher base wins despite dev", error propagationisDevUpdateAvailable: All update scenarios including the important "stable release is an update from dev" case (Line 121)The sign-comparison pattern for
wantCmpvalues is appropriate for comparison functions.cli/cmd/config.go (1)
36-51: Clean implementation ofconfig setcommand using Cobra patterns.The implementation correctly:
- Validates key against
supportedConfigKeyswith a clear error message- Validates values using
config.IsValidChannel/config.IsValidLogLevelwith valid options in error messages- Loads existing config, mutates, and persists via
config.Save()- Provides user feedback via
out.Success()As per coding guidelines: Uses Cobra framework correctly for CLI commands.
Also applies to: 97-127
cli/internal/config/state.go (1)
19-19: LGTM! Channel field and validation properly implemented.The implementation correctly:
- Adds
Channelfield with JSON tag and"stable"default- Provides
DisplayChannel()for safe display of empty values- Uses
"warn"(not"warning") invalidLogLevelsto match actual system usage- Guards validation with empty-string checks so missing JSON fields use defaults
Past review concerns were addressed: log level validation uses
"warn"andvalidate()now checks bothChannelandLogLevel.Also applies to: 39-39, 49-55, 106-123, 165-170
cli/internal/config/state_test.go (1)
207-305: Thorough test coverage for channel and log level validation.The tests comprehensively verify:
IsValidChannel: Accepts onlystable/dev, rejects empty/unknown/case-variantsIsValidLogLevel: Correctly rejects"warning"(system uses"warn"), case-sensitiveDisplayChannel(): Returns"stable"for empty valuesLoad()validation: Rejects invalid values, allows empty values (falls back to defaults via unmarshalling ontoDefaultState())The comment on Line 281 ("empty log level uses default from DefaultState") accurately explains the behavior.
.github/workflows/dev-release.yml (5)
1-16: Good workflow structure with proper permissions and concurrency.
permissions: {}at workflow level withcontents: writeonly at job level follows least-privilege principleconcurrency: dev-releasewithcancel-in-progress: trueprevents race conditions between rapid pushes- Pinned action SHA (
actions/checkout@de0fac...) ensures reproducibility
24-48: Robust skip conditions for Release Please commits and existing stable tags.The skip logic correctly handles:
- Release Please version-bump merges (
chore(main): release)- Commits with
Release-As:trailer- Commits already tagged with a stable version (regex
^v[0-9]+\.[0-9]+\.[0-9]+$)
50-91: Version computation logic is sound.The algorithm correctly:
- Finds last stable tag (excludes
.devtags viagrep -vE)- Gets next version from Release Please pending PR, or falls back to patch bump
- Counts commits since last stable tag for the dev number
- Skips gracefully when no commits exist since last tag
115-131: Atomic tag+release creation addresses prior review concern.Using
gh release create "$DEV_TAG" --target "$GITHUB_SHA"creates both the tag and release atomically. This approach is cleaner than the previously suggested cleanup-on-failure pattern, as it avoids orphaned tags entirely by not creating the tag separately.This addresses the past review comment about partial failure leaving dangling tags.
132-146: Dev pre-release cleanup is well-implemented.The cleanup logic:
- Keeps the 5 most recent dev pre-releases (sorted by
createdAtdescending)- Uses
--cleanup-tagto remove associated tags when deleting releases- Uses
|| trueto continue on individual deletion failuresOne consideration: if
gh release listreturns fewer than 50 releases, the jq filter safely handles this.cli/internal/selfupdate/updater.go (7)
213-254: Version comparison logic is sound.The
compareWithDevfunction correctly implements the ordering:v0.4.7 > v0.4.7.dev3 > v0.4.7.dev2 > v0.4.6. ThesplitDevsilent fallback for malformed dev tags was previously flagged as a nitpick.
27-43: LGTM!Constants are well-organized. The
per_page=20is sufficient given the dev release cleanup policy keeps only 5 most recent dev pre-releases.
67-75: LGTM!Clean dispatch function with clear documentation. The explicit "dev" check with implicit stable fallback aligns with the design goal of preferring stable by default.
83-132: LGTM!Good use of generics with
fetchJSON[[]devRelease]. The conversion toReleaseforfindAssetsreuses existing logic cleanly. Error handling is comprehensive.
145-153: Pre-releases without.devsuffix are silently skipped.The condition
r.Prerelease && strings.Contains(r.TagName, ".dev")means pre-releases likev0.5.0-alphaorv0.5.0-rc1would be treated as neither dev nor stable, effectively ignored. This appears intentional per the PR objectives (only PEP 440.devNformat is supported), but worth confirming this is the desired behavior.
256-267: LGTM!The special case for
cur == "dev"correctly handles source builds whereversion.Versiondefaults to "dev", ensuring they always see updates as available.
269-299: LGTM!Clean refactor leveraging the generic
fetchJSON[Release]. The structure now mirrorsCheckDevFromURLfor consistency.
Replace per-call http.Client allocation with a package-level apiClient (30s timeout). Keeps the download path's separate client with longer timeout (5min) unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…716) ## Summary - Tags created with the default `GITHUB_TOKEN` do not fire `push` events for other workflows (GitHub Actions anti-recursion safeguard) - The `v0.4.7.dev3` dev pre-release was created successfully but Docker and CLI workflows never triggered - Switch to `RELEASE_PLEASE_TOKEN` (PAT) for the `gh release create --target` step so downstream workflows trigger on dev tags - Cleanup step keeps using `github.token` since it doesn't need to trigger anything ## Context After merging #715, the dev-release workflow ran and created `v0.4.7.dev3` correctly, but the Docker and CLI pipelines never fired. This is the same pattern used by `release.yml` which uses a PAT for Release Please to ensure tag-triggered workflows run. ## Test plan - [ ] Push to main triggers `dev-release.yml`, creates dev tag + pre-release - [ ] Docker workflow triggers on the dev tag (was broken before this fix) - [ ] CLI workflow triggers on the dev tag (was broken before this fix) - [ ] Finalize-release correctly skips dev pre-releases (unchanged) --------- Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
#729) ## Summary - Switch dev tag format from PEP 440 (`v0.4.7.dev3`) to semver (`v0.4.7-dev.3`) so GoReleaser can parse them - Create dev releases as **draft** pre-releases instead of published, so they flow through the exact same finalize-release pipeline as stable releases - Remove the dev exclusion guard from finalize-release -- both stable and dev releases now use the same lifecycle ## Why After merging #715 and #716, the dev-release workflow correctly created tags and triggered downstream pipelines, but both failed: 1. **CLI**: GoReleaser rejected `v0.4.7.dev4` as invalid semver (`failed to parse tag as semver`) 2. **Docker**: SBOM attachment failed because dev releases were created as published (immutable), blocking asset uploads ## How it works now Same pipeline, zero special-casing: 1. `dev-release.yml` creates **draft** pre-release + tag (via PAT) 2. Docker workflow triggers on tag -- builds, scans, pushes, attaches SBOMs to draft 3. CLI workflow triggers on tag -- GoReleaser builds binaries, attaches to draft 4. `finalize-release.yml` publishes the draft once both succeed This is identical to the stable release flow. ## Changes - `dev-release.yml`: semver tag format (`-dev.N`), `--draft --prerelease`, updated grep/jq filters - `docker.yml`: `.dev` -> `-dev.` in all contains() checks - `finalize-release.yml`: removed `!contains(.dev)` guard -- handles both stable and dev - `cli/internal/selfupdate/updater.go`: `splitDev` and `selectBestRelease` parse `-dev.` format - `cli/internal/selfupdate/updater_version_test.go`: all test cases updated - `cli/internal/selfupdate/updater_test.go`: integration test cases updated - `CLAUDE.md`: updated tag examples and descriptions - Cleaned up old `v0.4.7.dev3` and `v0.4.7.dev4` releases/tags ## Test plan - [ ] Push to main triggers `dev-release.yml`, creates `v0.4.7-dev.N` tag + **draft** pre-release - [ ] Docker workflow triggers, builds all 3 images, attaches SBOMs to draft - [ ] CLI workflow triggers, GoReleaser builds binaries, attaches to draft - [ ] `finalize-release` publishes the draft after both succeed - [ ] `go test ./...` passes (verified locally) - [ ] `synthorg update` on dev channel finds semver dev releases Closes #713 Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
🤖 I have created a release *beep* *boop* --- ## [0.4.7](v0.4.6...v0.4.7) (2026-03-22) ### Features * add system user for CLI-to-backend authentication ([#710](#710)) ([dc6bd3f](dc6bd3f)) * dev channel builds with incremental pre-releases between stable releases ([#715](#715)) ([0e8a714](0e8a714)) * replace hardcoded name pools with Faker multi-locale name generation ([#714](#714)) ([5edc6ec](5edc6ec)) ### Bug Fixes * dev-release tag creation, dependabot coverage, go -C cli convention ([#730](#730)) ([7634843](7634843)) * improve name generation step UX and fix sentinel expansion bug ([#739](#739)) ([f03fd05](f03fd05)) * settings page UX polish -- toggle bug, source badges, form improvements ([#712](#712)) ([d16a0ac](d16a0ac)) * switch dev tags to semver and use same release pipeline as stable ([#729](#729)) ([4df6b9b](4df6b9b)), closes [#713](#713) * unify CLI image discovery and standardize Go tooling ([#738](#738)) ([712a785](712a785)) * use PAT in dev-release workflow to trigger downstream pipelines ([#716](#716)) ([d767aa3](d767aa3)) ### CI/CD * bump astral-sh/setup-uv from 7.4.0 to 7.6.0 in /.github/actions/setup-python-uv in the minor-and-patch group ([#731](#731)) ([7887257](7887257)) * bump the minor-and-patch group with 3 updates ([#735](#735)) ([7cd253a](7cd253a)) * bump wrangler from 4.75.0 to 4.76.0 in /.github in the minor-and-patch group ([#732](#732)) ([a6cafc7](a6cafc7)) * clean up all dev releases and tags on stable release ([#737](#737)) ([8d90f5c](8d90f5c)) ### Maintenance * bump the minor-and-patch group across 2 directories with 2 updates ([#733](#733)) ([2b60069](2b60069)) * bump the minor-and-patch group with 3 updates ([#734](#734)) ([859bc25](859bc25)) * fix dependabot labels and add scope tags ([#736](#736)) ([677eb15](677eb15)) * remove redundant pytest.mark.timeout(30) markers ([#740](#740)) ([9ec2163](9ec2163)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Summary
v0.4.7.dev3) with full pipeline: Docker images, CLI binaries, cosign signatures, SLSA provenancestable/devupdate channels viasynthorg config set channel devv*tagsChanges
New workflow:
dev-release.ymlDocker workflow
devtag for dev builds (only onrefs/tags/v*.dev*)major.minortag on dev builds (avoids overwriting stable0.4tag)Finalize-release workflow
CLI (
cli/)Channelconfig field (stable/dev) with validationsynthorg config set channel dev/stablecommandsynthorg config showandsynthorg statusdisplay current channelCheckForChannel/CheckDevin selfupdate with dev-aware version comparisonfetchJSON[T]replaces duplicate HTTP fetch functionsUser-Agentheader on all GitHub API requestslog_levelvalidation with allowlist (was accepting arbitrary values)splitDev,compareWithDev,isDevUpdateAvailableDocs
Pre-PR Review
4 agents ran (go-reviewer, infra-reviewer, security-reviewer, docs-consistency), 18 findings addressed in the second commit.
Test plan
dev-release.yml, createsv0.4.7.devNtag + pre-releasedev+ version tagsfinalize-releasedoes NOT publish dev pre-releasessynthorg config set channel devpersists in config.jsonsynthorg updateon dev channel finds dev pre-releasesgo test ./...passes (including new version comparison tests)Closes #713