Skip to content

refactor: hermes adjustments#69

Merged
pedronauck merged 5 commits into
mainfrom
pn/hermes
Apr 25, 2026
Merged

refactor: hermes adjustments#69
pedronauck merged 5 commits into
mainfrom
pn/hermes

Conversation

@pedronauck
Copy link
Copy Markdown
Member

@pedronauck pedronauck commented Apr 25, 2026

Summary by CodeRabbit

  • New Features

    • Memory health & history API and CLI commands
    • MCP OAuth2 auth (login/status/logout) and per-server auth status
    • Config management CLI (show/get/set/validate/edit)
    • Durable scheduler with persistent cursor state, fire IDs and delivery diagnostics
    • Agent probe checks surfaced in health reports
    • Extensions and install output show required/missing environment variables
    • New lifecycle CLI (update/uninstall) and memory CLI subcommands
  • Improvements

    • Richer, redacted failure diagnostics with crash bundles and event failures
    • Enhanced observability: retention, persistence, failures and probe metrics
    • Improved process lifecycle tracking, scoped interrupts, and session stop/failure visibility
  • Bug Fixes

    • Symlink/path security hardening and safer .env repair/inspection

@pedronauck pedronauck self-assigned this Apr 25, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 25, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ce0e5142-9808-4b0e-8eff-e7dbccd918de

📥 Commits

Reviewing files that changed from the base of the PR and between 9739091 and 4669cb7.

⛔ Files ignored due to path filters (64)
  • .agents/skills/favicon-gen/SKILL.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/favicon-gen/assets/favicon-svg-circle.svg is excluded by !**/*.svg, !.agents/**
  • .agents/skills/favicon-gen/assets/favicon-svg-shield.svg is excluded by !**/*.svg, !.agents/**
  • .agents/skills/favicon-gen/assets/favicon-svg-square.svg is excluded by !**/*.svg, !.agents/**
  • .agents/skills/favicon-gen/assets/manifest.webmanifest is excluded by !.agents/**
  • .agents/skills/favicon-gen/references/extraction-methods.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/favicon-gen/references/format-guide.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/favicon-gen/references/monogram-patterns.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/favicon-gen/references/shape-templates.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/SKILL.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/async-patterns.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/bundling.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/data-patterns.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/debug-tricks.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/directives.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/error-handling.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/file-conventions.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/font.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/functions.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/hydration-error.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/image.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/metadata.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/parallel-routes.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/route-handlers.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/rsc-boundaries.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/runtime-selection.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/scripts.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/self-hosting.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/suspense-boundaries.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/seo-audit/SKILL.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/seo-audit/evals/evals.json is excluded by !**/*.json, !.agents/**
  • .agents/skills/seo-audit/references/ai-writing-detection.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/seo-audit/references/international-seo.md is excluded by !**/*.md, !.agents/**
  • .claude/agents/designer.md is excluded by !**/*.md, !.claude/**
  • .codex/plans/2026-04-20-prompt-stream-stall.md is excluded by !**/*.md
  • .codex/plans/2026-04-20-session-chat-production-hardening.md is excluded by !**/*.md
  • .codex/plans/2026-04-25-site-hardening.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/_meta.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_001.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_002.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_003.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_004.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_005.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_006.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_007.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_008.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_009.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_010.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_011.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_012.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_013.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_014.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_015.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_016.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_017.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_018.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_019.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_020.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_021.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_022.md is excluded by !**/*.md
  • AGENTS.md is excluded by !**/*.md
  • CLAUDE.md is excluded by !**/*.md
  • DESIGN.md is excluded by !**/*.md
  • package.json is excluded by !**/*.json
📒 Files selected for processing (38)
  • internal/acp/client.go
  • internal/acp/client_test.go
  • internal/cli/lifecycle.go
  • internal/cli/lifecycle_test.go
  • internal/cli/mcp_auth.go
  • internal/config/config.go
  • internal/config/config_test.go
  • internal/config/merge.go
  • internal/daemon/daemon.go
  • internal/daemon/daemon_test.go
  • internal/diagnostics/redact_test.go
  • internal/mcp/auth/service.go
  • internal/mcp/auth/service_test.go
  • internal/memory/store.go
  • internal/memory/store_test.go
  • internal/observe/health.go
  • internal/observe/observer_test.go
  • internal/retry/retry_test.go
  • internal/session/crash_bundle_test.go
  • internal/session/prompt_activity_test.go
  • internal/session/resume_repair_test.go
  • packages/site/app/error.tsx
  • packages/site/app/global.css
  • packages/site/app/global.test.ts
  • packages/site/app/layout.tsx
  • packages/site/app/not-found.tsx
  • packages/site/app/opengraph-image.tsx
  • packages/site/app/protocol/[[...slug]]/page.tsx
  • packages/site/app/protocol/layout.tsx
  • packages/site/app/robots.ts
  • packages/site/app/runtime/[[...slug]]/page.tsx
  • packages/site/app/runtime/layout.tsx
  • packages/site/app/sitemap.ts
  • packages/site/components/landing/final-cta.tsx
  • packages/site/components/landing/hero.tsx
  • packages/site/components/landing/primitives/code-block.test.tsx
  • packages/site/components/landing/primitives/code-block.tsx
  • packages/site/components/landing/primitives/cta-button.tsx

Walkthrough

Introduces a shared tool process registry and scoped interrupts, durable scheduler state and run claiming, expanded failure classification/redaction with crash bundles, MCP OAuth2-PKCE auth and token persistence, memory operation history and endpoints, observability retention, many API/DB schema changes, and broad CLI features and tests.

Changes

Cohort / File(s) Summary
Process registry & tooling
internal/acp/client.go, internal/acp/handlers.go, internal/acp/tool_host.go, internal/acp/types.go, internal/hooks/executor_subprocess.go, internal/extension/manager.go, internal/environment/local/provider.go, internal/environment/daytona/provider.go, internal/daemon/boot.go, internal/daemon/hooks_bridge.go, internal/daemon/daemon.go, internal/hooks/executor_test.go, internal/acp/launcher_tool_host_test.go
Add injectable *toolruntime.Registry options, propagate registry into tool hosts/hooks/extensions/daemon boot, register and checkpoint process/terminal records, and expose scoped Interrupt handling across runtime hosts and executors.
ACP client lifecycle, probes & failures
internal/acp/client.go, internal/acp/client_test.go, internal/acp/failure.go, internal/acp/failure_probe_test.go, internal/acp/probe.go, internal/acp/handlers.go, internal/acp/tool_host.go
Register AgentProcess records, bound process-record writes with timeout, add Driver.Interrupt and wired interrupt behavior, classify/wrap session failures, enrich prompt failure events, and add probing utilities with tests.
Failure model, redaction & crash bundles
internal/store/failure.go, internal/diagnostics/redact.go, internal/session/crash_bundle.go, internal/session/failure.go, internal/diagnostics/redact_test.go, internal/session/crash_bundle_test.go
Introduce FailureKind/SessionFailure model, normalization/validation/cloning, redaction helpers (Redact/RedactAndBound), crash-bundle writer/attachment and related tests.
Session lifecycle & scoped interrupts
internal/session/interfaces.go, internal/session/session.go, internal/session/manager_lifecycle.go, internal/session/manager_start.go, internal/session/manager_prompt.go, internal/session/prompt_activity.go, internal/session/liveness.go, internal/session/manager_test.go, internal/session/additional_test.go
Persist failures and crash bundles, track active prompt turn IDs, add ScopedInterrupter support and ACP adapter Interrupt wiring, tighten startup/stop failure handling and tests.
Durable scheduler & automation runtime
internal/automation/schedule.go, internal/automation/manager.go, internal/automation/dispatch.go, internal/automation/model/types.go, internal/automation/model/persistence.go, internal/automation/model/validate.go, internal/automation/types.go, internal/automation/schedule_test.go, internal/automation/schedule_integration_test.go
Replace in-memory scheduler with durable cursor-driven scheduler, add SchedulerStore/SchedulerState, ClaimScheduledRun/reservation flow, misfire/catch-up tracking, and delivery-error recording; dispatch supports reserved runs.
Automation API & DB
internal/api/contract/automation.go, internal/api/core/automation.go, internal/api/core/automation_test.go, internal/store/globaldb/global_db_automation.go, internal/store/globaldb/global_db_automation_scheduler.go, internal/store/globaldb/global_db_automation_test.go
Extend API payloads with scheduler state and delivery metadata (fire_id, scheduled_at, delivery_error), enrich job/run payloads, add DB migrations and persistence/claiming/recording for scheduler state and delivery errors.
MCP OAuth2 PKCE & token persistence
internal/mcp/auth/types.go, internal/mcp/auth/metadata.go, internal/mcp/auth/pkce.go, internal/mcp/auth/service.go, internal/mcp/auth/service_test.go, internal/store/globaldb/global_db_mcp_auth.go, internal/store/globaldb/global_db_mcp_auth_test.go, internal/daemon/settings.go, internal/daemon/settings_test.go
New MCP auth package: metadata discovery, PKCE helpers, Service with BeginLogin/Exchange/Refresh/Logout/Status, persistent token store in GlobalDB, and daemon settings-side status wiring with tests.
MCP server config, redaction & settings
internal/config/provider.go, internal/config/mcpjson.go, internal/config/mcp_resource.go, internal/config/redaction.go, internal/config/merge.go, internal/config/provider_test.go, internal/api/contract/settings.go, internal/settings/models.go, internal/settings/service.go, internal/settings/collections.go
Extend MCPServer with Transport/URL/Auth, normalize/validate transport and auth, add redaction helpers (RedactedValue/RedactStringMap/RedactedMCPServer), and surface auth status in settings APIs and converters.
Memory operation history, API & CLI
internal/memory/types.go, internal/memory/catalog.go, internal/memory/store.go, internal/memory/store_test.go, internal/api/core/memory.go, internal/api/core/memory_workspace_test.go, internal/api/contract/contract.go, internal/api/httpapi/routes.go, internal/api/udsapi/routes.go, internal/api/spec/spec.go, internal/cli/memory.go, internal/cli/memory_test.go, internal/cli/client.go, internal/cli/client_test.go
Introduce Operation/OperationRecord, history query APIs and migration for memory_operation_log, implement Store.History, add MemoryHealth/MemoryHistory endpoints and CLI commands, plus tests with redaction and filtering.
Observability & retention
internal/observe/observer.go, internal/observe/health.go, internal/observe/retention.go, internal/store/globaldb/global_db_observe.go, internal/store/globaldb/global_db_test.go, internal/api/core/conversions.go, internal/cli/observe.go
Add retention subsystem with SweepObservability DB impl and background loop, enhanced health payloads (persistence/retention/failures/agent_probes), probe integration, conversion and CLI support, and tests.
Toolruntime persistence & schema
internal/store/globaldb/global_db_toolruntime.go, internal/store/globaldb/global_db.go
Add tool_processes table CRUD (Upsert/Update/List), include tool/process migrations in schema list, and tighten DB file permission handling.
Retry utilities & bridgesdk
internal/retry/retry.go, internal/retry/retry_test.go, internal/bridgesdk/errors.go, internal/bridgesdk/errors_test.go
Add retry package with policy-based delays, jitter, and Wait; update bridgesdk to use retrypkg.Wait/Delay and adjust retry tests.
Process-group helpers
internal/procutil/process_group_unix.go, internal/procutil/process_group_windows.go
Add cross-platform process-group signaling/wait/kill helpers; Unix implements drain/poll semantics, Windows returns unsupported sentinel errors.
CLI surface & helpers
internal/cli/config.go, internal/cli/config_test.go, internal/cli/lifecycle.go, internal/cli/lifecycle_test.go, internal/cli/mcp_auth.go, internal/cli/mcp_auth_test.go, internal/cli/extension.go, internal/cli/install.go, internal/cli/memory.go, internal/cli/...
Add extensive CLI features: config subcommands (show/list/get/set/path/edit/validate), lifecycle (update/uninstall/purge), MCP auth commands (login/status/logout with PKCE and loopback), memory commands, extension env reporting, and many tests.
Extensions & skills security
internal/extension/manifest.go, internal/extension/describe.go, internal/extension/install_managed.go, internal/extension/reference_integration_test.go, internal/skills/path_security.go, internal/skills/loader.go, internal/skills/provenance.go
Add manifest requires_env handling + MissingEnv detection, include env diagnostics in status/CLI, and enforce path/symlink containment for skills/installs and hashed symlink guarding.
Various tests & converters
multiple files under internal/...
Extensive test additions/updates across ACP, automation, memory, MCP auth, config/dotenv, session, observe, globaldb, retry, and CLI to cover new behaviors, migrations, and redaction rules.

Sequence Diagram(s)

(Skipped — changes span multiple distinct subsystems and do not present a single focused 3+ component sequential flow to visualize simply.)

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
internal/api/httpapi/prompt.go (1)

137-151: ⚠️ Potential issue | 🟠 Major

Cancel prompt before detached drain begins.

Current ordering cancels only after draining, so the producer can continue running until drain timeout. This can keep prompt work alive after client disconnect and delay shutdown.

Suggested fix
 func (h *Handlers) drainPromptEventsAsync(
 	ctx context.Context,
 	events <-chan acp.AgentEvent,
 	cancelPrompt context.CancelFunc,
 ) {
-	if h == nil || cancelPrompt == nil {
+	if h == nil {
 		return
 	}
+	if cancelPrompt != nil {
+		cancelPrompt()
+	}
 	if ctx == nil {
-		cancelPrompt()
 		return
 	}
 	drainCtx, cancelDrain := context.WithTimeout(ctx, detachedPromptDrainTimeout)
 	h.promptDrainWG.Go(func() {
 		defer cancelDrain()
-		defer cancelPrompt()
 		h.drainPromptEvents(drainCtx, events)
 	})
 }

Also applies to: 163-174

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/httpapi/prompt.go` around lines 137 - 151, The code currently
calls h.drainPromptEventsAsync(...) and only then cancels via cancelOnReturn,
allowing the producer to keep running during the drain; change the ordering so
cancelOnReturn() is invoked before starting the detached drain to stop the
producer promptly, then set cancelOnReturn = nil and call
h.drainPromptEventsAsync(context.WithoutCancel(c.Request.Context()), events,
cancelOnReturn) immediately afterwards; apply the same reorder in both places
where drainPromptEventsAsync is invoked (the branch after state.emit error and
the branch handling closed events/finish involving state.finish and
h.StreamDoneChannel()) and ensure you nil out cancelOnReturn after calling it.
internal/api/core/more_coverage_test.go (1)

166-181: ⚠️ Potential issue | 🟡 Minor

Assert the mapped failure summary too.

The fixture sets Failure.Summary, but the assertion only verifies Kind. If summary propagation breaks, this test still passes.

As per coding guidelines, Ensure tests verify behavior outcomes, not just function calls.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/core/more_coverage_test.go` around lines 166 - 181, Add an
assertion to verify the mapped failure summary matches the fixture: after the
nil/Kind checks for agentEvent.Failure, assert that agentEvent.Failure.Summary
== "permission policy denied" (or use the same literal/variable from the
fixture) and call t.Fatalf with a descriptive message if it does not match; this
ensures the Summary field from store.SessionFailure is propagated correctly.
internal/cli/session.go (1)

451-484: ⚠️ Potential issue | 🟡 Minor

Add stop_detail to Toon output for parity with human output.

Line 419 exposes Stop Detail in human format, but Toon omits it. This drops useful diagnostic context for structured CLI consumers.

🔧 Proposed fix
 			return renderToonObject("session", []string{
 				"id",
 				"name",
 				"agent_name",
 				"provider",
 				"environment_backend",
 				"workspace",
 				"channel",
 				"state",
 				"stop_reason",
+				"stop_detail",
 				"failure_kind",
 				"failure_summary",
 				"crash_bundle_path",
 				"acp_session_id",
 				"created_at",
 				"updated_at",
 			}, []string{
 				info.ID,
 				info.Name,
 				info.AgentName,
 				info.Provider,
 				sessionEnvironmentBackend(info),
 				displaySessionWorkspace(info),
 				info.Channel,
 				string(info.State),
 				string(info.StopReason),
+				info.StopDetail,
 				sessionFailureKind(info),
 				sessionFailureSummary(info),
 				sessionCrashBundlePath(info),
 				info.ACPSessionID,
 				formatTime(info.CreatedAt),
 				formatTime(info.UpdatedAt),
 			}), nil
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/session.go` around lines 451 - 484, The Toon output omits the
"stop_detail" field; update the toon closure that calls
renderToonObject("session", ...) to include "stop_detail" in the header list and
add the corresponding value (use the existing helper sessionStopDetail(info)) in
the values slice so Toon matches the human output; modify the toon function that
builds the two string slices (header names and values) to insert "stop_detail"
and sessionStopDetail(info) in the same relative position as the human
rendering.
internal/store/globaldb/global_db_automation.go (1)

508-516: ⚠️ Potential issue | 🟠 Major

List/filter runs by an effective event timestamp, not only started_at.

Runs that fail during reservation or delivery can now have scheduled_at / delivery_error_at set while started_at stays NULL. Keeping both the sort order and the Since/Until predicates anchored to started_at means recent delivery failures fall to the bottom and can disappear entirely from time-windowed history queries.

Also applies to: 1429-1438

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/store/globaldb/global_db_automation.go` around lines 508 - 516, The
query currently orders and filters by started_at only, which hides runs that
never started but have scheduled_at or delivery_error_at; change ordering and
time-window predicates to use an effective event timestamp (e.g.,
COALESCE(started_at, delivery_error_at, scheduled_at) or a GREATEST/COALESCE
expression) instead of started_at alone. Update the SQL in
global_db_automation.go where sqlQuery is built (the sqlQuery variable,
AppendWhere/AppendLimit usage) and update buildAutomationRunClauses to apply the
same effective timestamp for Since/Until predicates; make the same change in the
other occurrence referenced (lines ~1429-1438) so both ORDER BY and any time
range filters use the effective timestamp. Ensure the chosen expression is used
consistently in SELECT/ORDER BY and in WHERE clauses so runs with scheduled_at
or delivery_error_at are correctly included and sorted.
internal/memory/store.go (1)

802-846: 🛠️ Refactor suggestion | 🟠 Major

Accept caller context for mutation operations to enable proper cancellation of catalog/database work.

The Write() and Delete() methods should accept context.Context as the first parameter and propagate it through syncScopeAfterMutation() and logMutationEvent() to the underlying catalog operations. Currently, these methods are called from API handlers (where request context is available) but cannot pass it, forcing the mutation helpers to use context.Background(). This makes catalog sync and history logging uncancellable, leaving them vulnerable to indefinite hangs on stuck database operations.

Per coding guidelines, functions crossing runtime boundaries should accept context and avoid context.Background() outside main and focused tests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/memory/store.go` around lines 802 - 846, The mutation helpers
(Write/Delete) must accept a context.Context and propagate it so
catalog/database work can be cancelled: change the signatures of Write and
Delete to take ctx context.Context as the first parameter, update calls to
syncScopeAfterMutation and logMutationEvent to pass that ctx, and modify
syncScopeAfterMutation(ctx context.Context, scope Scope, filename string) and
logMutationEvent(ctx context.Context, action string, scope Scope, filename
string) so they use ctx when calling syncScope(ctx, ...) and
logCatalogEvent(ctx, ...). Ensure logCatalogEvent is called with the incoming
ctx (it already accepts ctx) and remove uses of context.Background() inside
these mutation-path helpers so all catalog sync/logging uses the caller-provided
context.
internal/automation/manager.go (1)

1971-1991: ⚠️ Potential issue | 🟠 Major

Don’t use the caller context for post-write scheduler reconciliation.

By the time applyJobToRuntime runs, the store mutation has already succeeded at its call sites. If the API/CLI context is canceled here, Register/Update can fail even though the durable job change is committed, and the rollback paths above reuse that same canceled context. That leaves the persisted job definition and in-memory scheduler out of sync until restart. Use a manager-owned runtime context, or context.WithoutCancel(ctx) with a short timeout, for the scheduler mutation path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/automation/manager.go` around lines 1971 - 1991, In
applyJobToRuntime, avoid using the caller context for scheduler reconciliation:
create and use a manager-owned non-cancelable runtime context (or wrap ctx with
context.WithoutCancel and a short timeout) when calling scheduler.State,
scheduler.Update, and scheduler.Register so transient cancellation of the
API/CLI caller doesn’t make Update/Register fail after the durable store
changed; replace uses of the incoming ctx in Manager.applyJobToRuntime for the
post-write scheduler mutation path (State, Update, Register) with that new
runtime context and ensure rollback/retry paths also use it rather than the
original caller context.
internal/config/provider.go (1)

461-517: ⚠️ Potential issue | 🟠 Major

Name-based merges can't clear inherited remote config.

mergeMCPServer and mergeMCPAuthConfig only copy non-empty override fields. That means an overlay can switch a base server to transport=stdio, but it cannot remove inherited url or auth, so the merged config stays invalid and the override cannot take effect. This needs an explicit clearing or full-replacement path when transport/auth changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/config/provider.go` around lines 461 - 517, mergeMCPServer and
mergeMCPAuthConfig currently only copy non-empty fields which prevents an
overlay from clearing inherited fields when changing transport or auth; update
mergeMCPServer so that when override.Transport is provided and differs from the
base transport you reset transport-dependent fields (e.g., set merged.URL = ""
and set merged.Auth to an empty MCPAuthConfig via clone zero) before applying
the override.Transport and other override fields, and update mergeMCPAuthConfig
so that when override.Type is provided and differs from base.Type you perform a
full-replacement (return a clone of override or set merged =
cloneMCPAuthConfig(override)) instead of merging individual fields; also ensure
an explicit empty/zero override.Auth (override.IsZero()) can clear inherited
auth when desired.
🟠 Major comments (26)
internal/config/release_config_test.go-11-84 (1)

11-84: 🛠️ Refactor suggestion | 🟠 Major

Refactor into t.Run("Should...") subtests (table-driven where repeated).

This test is currently monolithic; split assertions into subtests so failures are isolated and guideline-compliant.

♻️ Suggested structure
 func TestGoReleaserConfigPreservesTrustArtifactsAndPackageTargets(t *testing.T) {
 	t.Parallel()

 	root := findRepoRootForReleaseConfigTest(t)
 	data, err := os.ReadFile(filepath.Join(root, ".goreleaser.yml"))
 	if err != nil {
 		t.Fatalf("os.ReadFile(.goreleaser.yml) error = %v", err)
 	}

 	var cfg map[string]any
 	if err := yaml.Unmarshal(data, &cfg); err != nil {
 		t.Fatalf("yaml.Unmarshal(.goreleaser.yml) error = %v", err)
 	}
-
-	checksum := mapAt(t, cfg, "checksum")
-	...
-	nfpms := sliceAt(t, cfg, "nfpms")
-	...
+
+	t.Run("Should preserve checksum configuration", func(t *testing.T) {
+		t.Parallel()
+		checksum := mapAt(t, cfg, "checksum")
+		if got, want := stringAt(t, checksum, "name_template"), "checksums.txt"; got != want {
+			t.Fatalf("checksum.name_template = %q, want %q", got, want)
+		}
+		if got, want := stringAt(t, checksum, "algorithm"), "sha256"; got != want {
+			t.Fatalf("checksum.algorithm = %q, want %q", got, want)
+		}
+	})
+
+	for _, artifact := range []string{"archive", "package", "source"} {
+		artifact := artifact
+		t.Run("Should preserve sbom artifact "+artifact, func(t *testing.T) {
+			t.Parallel()
+			assertSBOMArtifact(t, sliceAt(t, cfg, "sboms"), artifact)
+		})
+	}
 }

As per coding guidelines, **/*_test.go: "MUST use t.Run("Should...") pattern for ALL test cases" and "Use table-driven tests with subtests (t.Run) as default pattern for Go tests".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/config/release_config_test.go` around lines 11 - 84, The test
TestGoReleaserConfigPreservesTrustArtifactsAndPackageTargets is
monolithic—refactor it into t.Run subtests (use "Should..." naming) and convert
repeated assertions into table-driven subtests; for example, wrap top-level
checks (checksum, signs, sboms via assertSBOMArtifact, homebrew_casks, nfpms)
into separate t.Run blocks and for repeated checks (like verifying sbom artifact
types and nfpm formats) create table-driven loops that call t.Run for each case,
keeping helper calls (findRepoRootForReleaseConfigTest, mapAt, stringAt,
sliceAt, asMap, stringSliceContains, assertSBOMArtifact) intact and moving their
related assertions into the appropriate subtest closures so failures are
isolated.
internal/skills/provenance_test.go-80-106 (1)

80-106: ⚠️ Potential issue | 🟠 Major

Add t.Run() subtest and replace string error matching with typed error assertion

This test violates two coding guidelines: it bypasses the required t.Run("ShouldRejectSymlinkEscape", ...) subtest pattern and relies on brittle strings.Contains(err.Error(), "reject hashed symlink") matching at line 103.

Required changes:

  1. Wrap test logic in t.Run("ShouldRejectSymlinkEscape", func(t *testing.T) { ... })
  2. Define a sentinel error (e.g., var ErrSymlinkEscape = errors.New(...)) in provenance.go and return it from ComputeDirectoryHash()
  3. Replace line 103's string check with errors.Is(err, ErrSymlinkEscape) or a typed error assertion via errors.As()

The production code currently wraps errors with message text only (fmt.Errorf("skills: reject hashed symlink %q: %w", ...)), but must expose a comparable error identity for proper testing per coding guidelines: "Use errors.Is() and errors.As() for error matching — never compare error strings."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/skills/provenance_test.go` around lines 80 - 106, The test should be
converted into a t.Run subtest and assert a typed sentinel error instead of
matching the error string: wrap the existing test body inside
t.Run("ShouldRejectSymlinkEscape", func(t *testing.T) { ... }), add a
package-level sentinel error (e.g., var ErrSymlinkEscape = errors.New("reject
hashed symlink")) in provenance.go, have ComputeDirectoryHash return that
sentinel (or wrap it with fmt.Errorf(...%w...)) when a hashed symlink escape is
detected, and update the test to replace strings.Contains(err.Error(), ...) with
errors.Is(err, ErrSymlinkEscape) (or errors.As if using a typed error).
internal/bridgesdk/errors_test.go-229-261 (1)

229-261: ⚠️ Potential issue | 🟠 Major

Refactor added cases into t.Run("Should...") table-driven subtests.

The new scenarios are bundled as inline assertions rather than explicit Should... subtests, which makes case isolation/reporting weaker and conflicts with the enforced test pattern.

As per coding guidelines, "**/*_test.go: Use table-driven tests with subtests (t.Run) as default pattern for Go tests" and "MUST use t.Run(\"Should...\") pattern for ALL test cases".

Also applies to: 291-331

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/bridgesdk/errors_test.go` around lines 229 - 261, Refactor
TestRetryDoAppliesDefaultsAndStopsWhenDelayContextCancels to use t.Run subtests
(pattern "Should...") and a table-driven structure: split the initial
default-attempt case and the cancel-during-delay case into separate
t.Run("Should...") subtests (each exercising RetryDo with the appropriate
RetryConfig, OnRetry callback, context cancellation and assertions), and if
there are multiple similar scenarios around lines 291-331 fold them into a loop
over a slice of test cases that calls t.Run(tc.name, func(t *testing.T){...})
while keeping references to the same functions/types (RetryDo, RetryConfig,
OnRetry, TransientError) so each case is isolated and reported independently.
internal/retry/retry_test.go-10-203 (1)

10-203: ⚠️ Potential issue | 🟠 Major

Align this suite with the required Should... subtest pattern.

The scenarios are strong, but the file should be organized as table-driven t.Run("Should...") subtests to match the repository’s mandatory test style.

As per coding guidelines, "**/*_test.go: Use table-driven tests with subtests (t.Run) as default pattern for Go tests" and "MUST use t.Run(\"Should...\") pattern for ALL test cases".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/retry/retry_test.go` around lines 10 - 203, Refactor the tests so
each scenario is a subtest using t.Run("Should...") (keeping existing
names/semantics) instead of standalone Test* functions: create a single parent
test (or groupings) that iterates a table of cases and calls t.Run with
descriptive "Should ..." names for each original scenario (e.g., the logic
inside TestDoRetriesUntilSuccessWithDeterministicJitter,
TestDoStopsAtMaxAttemptsAndDoesNotSleepAfterFinalFailure,
TestDoHonorsContextCancellation, TestDoValueStopsOnNonRetryableAndContextErrors,
TestDoRejectsNilInputs, TestWaitHonorsContextCancellation,
TestWaitHandlesNilContextAndNonPositiveDelay,
TestDelayAppliesJitterBoundsAndCap); move t.Parallel() into each subtest as
appropriate, preserve all assertions and helper usage (DoValue, Do, Wait, Delay,
equalDurations, sequenceRand, etc.), and keep test behavior identical while
updating names to follow the "Should ..." pattern.
internal/bridgesdk/errors.go-344-345 (1)

344-345: ⚠️ Potential issue | 🟠 Major

Wrap retry wait failures with stage context.

This return path drops call-site context. Please wrap the error so downstream logs/diagnostics show that cancellation/failure happened during retry backoff waiting.

Suggested fix
 		if err := retrypkg.Wait(ctx, delay); err != nil {
-			return zero, err
+			return zero, fmt.Errorf("bridge retry wait: %w", err)
 		}

As per coding guidelines, "Use explicit error returns with wrapped context: fmt.Errorf(\"context: %w\", err)".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/bridgesdk/errors.go` around lines 344 - 345, The error returned from
retrypkg.Wait(ctx, delay) is returned raw (return zero, err) losing stage
context; change the return to wrap the error with contextual text (e.g., "retry
wait" or "waiting for retry backoff") using fmt.Errorf so downstream logs show
this occurred during the retry wait stage, and add fmt to imports if
needed—target the retrypkg.Wait call (with variable delay) and the return that
currently uses zero and err.
internal/retry/retry.go-77-95 (1)

77-95: ⚠️ Potential issue | 🟠 Major

Wrap retry-loop propagated errors with attempt/stage context.

These returns currently pass upstream errors through raw, which makes failure provenance harder to trace during operations.

Suggested fix
 import (
 	"context"
 	"errors"
+	"fmt"
 	"math"
 	"math/rand"
 	"time"
 )
@@
 		if ctxErr := ctx.Err(); ctxErr != nil {
-			return zero, ctxErr
+			return zero, fmt.Errorf("retry: context done after attempt %d: %w", attempt, ctxErr)
 		}
 		if isContextError(err) || attempt == policy.MaxAttempts || !retryable(shouldRetry, err) {
-			return zero, err
+			return zero, fmt.Errorf("retry: attempt %d failed: %w", attempt, err)
 		}
@@
 		if err := policy.Sleep(ctx, delay); err != nil {
-			return zero, err
+			return zero, fmt.Errorf("retry: wait before attempt %d failed: %w", attempt+1, err)
 		}

As per coding guidelines, "Use explicit error returns with wrapped context: fmt.Errorf(\"context: %w\", err)".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/retry/retry.go` around lines 77 - 95, The retry loop is returning
raw errors which loses provenance; update the three return points to wrap errors
with attempt/stage context using fmt.Errorf so callers see which attempt failed.
Specifically, when returning ctx.Err(), wrap it like fmt.Errorf("context
canceled during retry attempt %d/%d: %w", attempt, policy.MaxAttempts, ctxErr);
when returning the propagated err (the branch checking
isContextError/attempt==MaxAttempts/!retryable), wrap as fmt.Errorf("retry
failed on attempt %d/%d: %w", attempt, policy.MaxAttempts, err); and when
returning the error from policy.Sleep(ctx, delay), wrap it as fmt.Errorf("sleep
failed on attempt %d/%d after delay %s: %w", attempt, policy.MaxAttempts, delay,
err). Use the existing symbols Delay, Attempt, policy.OnRetry, retryable and
policy.Sleep to locate the code to change.
internal/diagnostics/redact.go-12-14 (1)

12-14: ⚠️ Potential issue | 🟠 Major

Quoted JSON secrets still bypass redaction.

secretPattern only matches unquoted key:value / key=value shapes, so inputs like "access_token":"abc" or "refresh_token":"abc" remain intact unless the value also happens to match the bearer-token regex. Since this helper feeds persisted diagnostics, that can leak credentials into crash bundles and failure summaries.

internal/cli/lifecycle.go-201-203 (1)

201-203: ⚠️ Potential issue | 🟠 Major

Treat “already exited” as success during uninstall.

There’s a race between daemonInfo(...running) and signalProcess. If the daemon exits in that window, SIGTERM can return ESRCH/os.ErrProcessDone and uninstall aborts even though the target state is already satisfied. This should continue to artifact cleanup instead of failing the command.

Suggested change
 	if err := deps.signalProcess(info.PID, syscall.SIGTERM); err != nil {
+		if errors.Is(err, syscall.ESRCH) || errors.Is(err, os.ErrProcessDone) {
+			return false, nil
+		}
 		return false, fmt.Errorf("cli: stop daemon for uninstall: %w", err)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/lifecycle.go` around lines 201 - 203, The uninstall flow should
treat "process already exited" as success: in the block that calls
deps.signalProcess (the call using info.PID), catch the error and if it is
syscall.ESRCH or os.ErrProcessDone (use errors.Is to match) then swallow it and
continue to artifact cleanup instead of returning an error; only return the
formatted error ("cli: stop daemon for uninstall: %w") for other error values.
Ensure you reference deps.signalProcess and the surrounding uninstall logic that
follows the earlier daemonInfo(...running) check.
internal/diagnostics/redact.go-29-37 (1)

29-37: ⚠️ Potential issue | 🟠 Major

Non-positive budgets currently disable the bound entirely.

When maxBytes <= 0, this returns the full redacted payload instead of a bounded result. That breaks the function contract and can still overflow storage limits if a caller passes 0 or a negative budget.

Suggested change
 func RedactAndBound(text string, maxBytes int) string {
 	redacted := strings.TrimSpace(Redact(text))
-	if maxBytes <= 0 || len(redacted) <= maxBytes {
+	if maxBytes <= 0 {
+		return ""
+	}
+	if len(redacted) <= maxBytes {
 		return redacted
 	}
 	if maxBytes <= len("...[truncated]") {
 		return redacted[:maxBytes]
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/diagnostics/redact.go` around lines 29 - 37, The function
RedactAndBound currently treats maxBytes <= 0 as "no bound" and returns the full
redacted text; change it so non-positive budgets are enforced: in
RedactAndBound, if maxBytes <= 0 return an empty string (or a minimal bounded
value) immediately, otherwise proceed with the existing truncation logic using
the redacted variable and the "...[truncated]" suffix; ensure you update the
initial conditional that now reads "if maxBytes <= 0 || len(redacted) <=
maxBytes" to first handle maxBytes <= 0, then the len(redacted) <= maxBytes
check, and keep the existing truncation branch that computes
redacted[:maxBytes-len("...[truncated]")] + "...[truncated]".
internal/session/prompt_activity.go-21-22 (1)

21-22: ⚠️ Potential issue | 🟠 Major

Avoid hardcoded stop timeout in runtime supervision path.

Line 21 introduces a fixed 5s deadline that overrides runtime configuration when stopping timed-out sessions. This makes stop behavior non-configurable and inconsistent with the rest of supervision settings.

Suggested fix
 const (
 	runtimeActivityKindPromptStarted = "prompt_started"
 	runtimeActivityKindAgentWaiting  = "agent_waiting"
 	runtimeActivityKindWarning       = "warning"
 	runtimeActivityKindTimeout       = "timeout"
-
-	runtimeTimeoutStopDeadline = 5 * time.Second
 )

@@
-	stopCtx, stopCancel := context.WithTimeout(context.WithoutCancel(s.ctx), runtimeTimeoutStopDeadline)
+	stopCtx, stopCancel := context.WithTimeout(context.WithoutCancel(s.ctx), s.config.TimeoutCancelGrace)

As per coding guidelines, "Never hardcode configuration — use TOML config or functional options."

Also applies to: 268-269

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/prompt_activity.go` around lines 21 - 22, The hardcoded
runtimeTimeoutStopDeadline = 5 * time.Second must be replaced with a
configurable value: remove the fixed declaration and read the stop timeout from
the existing supervision configuration or a functional option (e.g., a field on
the session/manager config or a StopTimeout option) and fall back to a sensible
default if unset; update all uses of runtimeTimeoutStopDeadline (including the
runtime supervision stop path referenced around the other occurrences) to use
the configured value (e.g., cfg.StopTimeout or opts.StopTimeout) so the timeout
is not hardcoded and can be set via TOML or options.
internal/session/liveness.go-32-35 (1)

32-35: ⚠️ Potential issue | 🟠 Major

Preserve an existing meta.Failure instead of overwriting it.

These recovery branches always replace meta.Failure with a new {Kind, Summary} pair. If the persisted session already carried richer failure data, such as a crash-bundle path, restart recovery silently discards it. Prefer starting from meta.Failure and only filling missing Kind/Summary before normalizing.

Also applies to: 42-45, 52-55

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/liveness.go` around lines 32 - 35, The current recovery
branches overwrite existing failure metadata by assigning next.Failure =
normalizeSessionFailure(&store.SessionFailure{...}, next.StopDetail); instead,
preserve any existing failure data (meta.Failure / next.Failure) and only
populate missing Kind and Summary fields before normalizing: read the existing
next.Failure (or meta.Failure) as a base, set Kind = store.FailureProcess and/or
Summary = next.StopDetail only if they are empty, then call
normalizeSessionFailure on that enriched failure object; apply the same change
in the other recovery branches referenced (the assignments at the other two
locations: lines 42-45 and 52-55).
internal/environment/daytona/provider.go-38-38 (1)

38-38: ⚠️ Potential issue | 🟠 Major

Wire processRegistry into the Daytona tool-host path.

This option only stores the registry on daytonaProvider; nothing in this file actually reads p.processRegistry. As a result, Daytona-owned tool processes still bypass the shared registry and won't participate in the new lifecycle/interrupt tracking.

Also applies to: 100-105

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/environment/daytona/provider.go` at line 38, The daytonaProvider
stores processRegistry but never wires it into the Daytona tool-host creation
path, so Daytona-owned tool processes bypass the shared registry; update the
code that constructs the Daytona tool host (the factory/constructor used in this
file where daytonaProvider creates tool hosts) to accept and use
p.processRegistry—either by passing p.processRegistry into the constructor
(e.g., NewDaytonaToolHost/NewToolHost) or by setting the host's registry field
after creation (host.Registry = p.processRegistry) so that spawned Daytona
processes participate in the shared lifecycle/interrupt tracking.
internal/api/core/automation_test.go-781-887 (1)

781-887: 🛠️ Refactor suggestion | 🟠 Major

Refactor into subtests using t.Run("Should...") pattern.

This test validates three distinct functions (AutomationHealthPayloadFromStatus, JobPayloadsFromJobs, RunPayloadFromRun) with sequential assertions, but lacks the required t.Run subtests. Split into named subtests to match the repository's mandatory test pattern:

t.Run("Should expose scheduler state in health payload", ...)
t.Run("Should include scheduler state in job payload", ...)
t.Run("Should expose delivery error in run payload", ...)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/core/automation_test.go` around lines 781 - 887, The test
currently exercises three separate behaviors in one function; refactor
TestAutomationPayloadsExposeSchedulerStateAndDeliveryErrors into three t.Run
subtests named "Should expose scheduler state in health payload", "Should
include scheduler state in job payload", and "Should expose delivery error in
run payload". For each subtest, move the related setup and assertions into its
own t.Run closure and call t.Parallel() inside each subtest; keep shared
fixtures (dates/schedulerState) defined in the outer test if needed or duplicate
minimal setup per subtest. Ensure the assertions remain the same and reference
the tested functions AutomationHealthPayloadFromStatus, JobPayloadsFromJobs, and
RunPayloadFromRun respectively.
internal/acp/types.go-516-525 (1)

516-525: ⚠️ Potential issue | 🟠 Major

Wrap checkpoint error with operation context per coding guidelines.

Line 520 returns the underlying error directly without wrapped context. Use fmt.Errorf() to add diagnostic information consistent with other error returns in this package.

🔧 Proposed fix
 func (p *AgentProcess) checkpointProcessOwner(ctx context.Context) error {
 	if p == nil || p.processRecord == nil {
 		return nil
 	}
-	return p.processRecord.Checkpoint(ctx, toolruntime.ProcessCheckpoint{
+	if err := p.processRecord.Checkpoint(ctx, toolruntime.ProcessCheckpoint{
 		Owner: &toolruntime.ProcessOwner{
 			SessionID: p.SessionID,
 		},
-	})
+	}); err != nil {
+		return fmt.Errorf("acp: checkpoint process owner: %w", err)
+	}
+	return nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/acp/types.go` around lines 516 - 525, checkpointProcessOwner
currently returns the raw error from p.processRecord.Checkpoint; change it to
wrap that error with contextual information using fmt.Errorf (e.g.,
fmt.Errorf("checkpointProcessOwner: failed to checkpoint process %s: %w",
p.SessionID, err)). Locate the function checkpointProcessOwner on type
AgentProcess and wrap the error returned by p.processRecord.Checkpoint(ctx,
toolruntime.ProcessCheckpoint{...}) so the returned error includes operation
context and the original error via %w.
internal/procutil/process_group_windows.go-10-23 (1)

10-23: ⚠️ Potential issue | 🟠 Major

Windows implementation violates the documented blocking contract for process group shutdown.

WaitForProcessGroupIDExit returns success immediately without waiting, and KillProcessGroupIDAndWait only signals without waiting for the process group to exit. The Unix implementation polls until the group is gone or the deadline is exceeded. Callers expect blocking semantics after KillProcessGroupIDAndWait completes—they proceed with cleanup, restart, and port reuse with the assumption that the process tree has been torn down. This implementation allows child processes to remain running while callers proceed, creating races. Return an explicit unsupported error or implement actual process group termination and wait behavior instead of returning success prematurely.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/procutil/process_group_windows.go` around lines 10 - 23, The Windows
implementation currently returns success immediately from
WaitForProcessGroupIDExit and only signals in KillProcessGroupIDAndWait,
violating the blocking contract; update these functions
(WaitForProcessGroupIDExit, KillProcessGroupIDAndWait, and possibly
SignalProcessGroupID) to either implement proper termination-and-wait semantics
(e.g., enumerate and terminate child processes for pgid, then poll/wait until
none remain or deadline expires) or, if that cannot be implemented safely on
Windows, return a clear, documented "unsupported on Windows" error from
WaitForProcessGroupIDExit and KillProcessGroupIDAndWait so callers do not assume
teardown; ensure the error type/message is unique and used consistently so
callers can detect and handle the unsupported case.
internal/daemon/agent_probes.go-78-85 (1)

78-85: ⚠️ Potential issue | 🟠 Major

Don't enqueue empty provider probes after resolution failures.

When ResolveProvider fails, provider.Command is the zero value, but the code still appends a target. That turns a config resolution problem into a guaranteed failed probe on every health pass. Skip the target after logging, or fall back to the raw configured command.

🛠 Suggested fix
 	provider, err := cfg.ResolveProvider(name)
-	if err != nil && logger != nil {
-		logger.Warn("daemon: resolve provider for probe health failed", "provider", name, "error", err)
-	}
+	if err != nil {
+		if logger != nil {
+			logger.Warn("daemon: resolve provider for probe health failed", "provider", name, "error", err)
+		}
+		continue
+	}
 	targets = append(targets, acp.ProbeTarget{
 		Provider: name,
 		Command:  strings.TrimSpace(provider.Command),
 	})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/daemon/agent_probes.go` around lines 78 - 85, The code currently
appends an acp.ProbeTarget using provider.Command even when
cfg.ResolveProvider(name) returns an error, causing empty/invalid probes to be
enqueued; in the block around ResolveProvider in agent_probes.go (look for
ResolveProvider, logger.Warn, and the targets = append(... acp.ProbeTarget{
Provider: name, Command: strings.TrimSpace(provider.Command) })), change the
logic to skip appending the probe when err != nil (after logging the warning)
or, if you prefer, use the original configured command as a fallback; ensure you
only append a ProbeTarget when you have a non-empty command (trimmed) to avoid
creating guaranteed-failing probes.
internal/session/crash_bundle.go-173-182 (1)

173-182: ⚠️ Potential issue | 🟠 Major

Preserve the timestamp when truncating crash bundle names.

base[:crashBundleNameMaxBytes] trims from the front of the assembled name, so a long sessionID can chop off the UnixNano suffix entirely. Repeated failures for the same session/kind then reuse the same filename and overwrite earlier crash bundles.

Suggested fix
 func crashBundleFileName(sessionID string, kind store.FailureKind, ts time.Time) string {
-	base := strings.Join([]string{
-		sanitizeCrashBundleName(sessionID),
-		sanitizeCrashBundleName(string(kind)),
-		fmt.Sprintf("%d", ts.UnixNano()),
-	}, "-")
-	if len(base) > crashBundleNameMaxBytes {
-		base = base[:crashBundleNameMaxBytes]
-	}
-	return base + ".json"
+	sessionPart := sanitizeCrashBundleName(sessionID)
+	if sessionPart == "" {
+		sessionPart = "unknown"
+	}
+	kindPart := sanitizeCrashBundleName(string(kind))
+	tsPart := fmt.Sprintf("%d", ts.UnixNano())
+	suffix := "-" + kindPart + "-" + tsPart
+	maxSessionBytes := crashBundleNameMaxBytes - len(suffix)
+	if maxSessionBytes < len("unknown") {
+		maxSessionBytes = len("unknown")
+	}
+	if len(sessionPart) > maxSessionBytes {
+		sessionPart = sessionPart[:maxSessionBytes]
+	}
+	return sessionPart + suffix + ".json"
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/crash_bundle.go` around lines 173 - 182, The current
crashBundleFileName builds base by joining sanitized sessionID, kind, and
ts.UnixNano but truncates with base[:crashBundleNameMaxBytes], which can drop
the timestamp; change truncation to preserve the timestamp suffix: after
assembling base (before adding ".json"), if len(base) > crashBundleNameMaxBytes
then set base = base[len(base)-crashBundleNameMaxBytes:] so the UnixNano
timestamp (from ts.UnixNano()) remains in the resulting filename; keep
references to crashBundleFileName, base, sanitizeCrashBundleName, ts.UnixNano(),
and crashBundleNameMaxBytes when making the edit.
internal/mcp/auth/metadata.go-19-21 (1)

19-21: ⚠️ Potential issue | 🟠 Major

Add a timeout to the default metadata client.

Falling back to http.DefaultClient means discovery has no client timeout, so a slow or wedged issuer can hang login/refresh indefinitely unless every caller always supplies a deadline on ctx. Prefer a dedicated client with a sane timeout, or require callers to provide one explicitly.

As per coding guidelines, external-call hazards like blocking calls without timeouts on request threads must be fixed before release.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/mcp/auth/metadata.go` around lines 19 - 21, Replace the fallback to
http.DefaultClient with a dedicated HTTP client that enforces a sane timeout
(e.g., set client = &http.Client{Timeout: 10 * time.Second}) to avoid indefinite
blocking when the issuer is slow; update the code around the client variable
assignment in internal/mcp/auth/metadata.go (the branch that currently does `if
client == nil { client = http.DefaultClient }`) and ensure you import time, or
alternatively change the function signature to require a non-nil client and
return an error if client == nil so callers must provide one.
internal/memory/store.go-466-475 (1)

466-475: ⚠️ Potential issue | 🟠 Major

Scope operation health metrics to the same visible workspaces.

operationStats(ctx) is aggregated across the entire shared catalog, while the entry/orphan counts above are filtered to workspaces. In a multi-workspace daemon, HealthStats(..., []string{workspaceA}) will report operation counts and last-operation timestamps produced by workspaceB.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/memory/store.go` around lines 466 - 475, operationStats(ctx) is
returning metrics for the whole catalog while IndexedFiles/OrphanedFiles are
already filtered to the current visible workspaces; change the code to compute
operation metrics scoped to the same workspaces by calling or adding a
workspace-scoped variant (e.g. s.catalog.operationStatsForWorkspaces(ctx,
workspaces) or similar) and use its returned operationCount and lastOperationAt
when constructing HealthStats so all fields (IndexedFiles, OrphanedFiles,
OperationCount, LastOperationAt) are consistently filtered to the same
workspaces.
internal/mcp/auth/metadata.go-68-88 (1)

68-88: ⚠️ Potential issue | 🟠 Major

Require HTTPS for OAuth discovery and credential endpoints.

Both resolveMetadataURL() and validateAbsoluteHTTPURL() accept plaintext HTTP for critical OAuth endpoints, enabling credential interception during metadata discovery, token exchange, and revocation flows. Apply HTTPS enforcement to:

  • Line 68–88: resolveMetadataURL() — enforce https:// scheme only
  • Line 113–121: validateAbsoluteHTTPURL() — reject http:// scheme

For local development, carve out an explicit loopback-only exception (e.g., localhost or 127.0.0.1).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/mcp/auth/metadata.go` around lines 68 - 88, Enforce HTTPS-only for
OAuth discovery and credential endpoints by updating resolveMetadataURL and
validateAbsoluteHTTPURL: after parsing the URL, reject any scheme that is not
"https" unless the host is a loopback address (allow "http" only for localhost,
127.0.0.1, or [::1]); specifically ensure parsed.Scheme == "https" or (scheme ==
"http" && hostIsLoopback(parsed.Host)), and return a clear error like "mcp auth:
insecure URL; https required" when rejected; add/replace a small helper
hostIsLoopback function or inline check to detect "localhost" and the loopback
IPs and apply the same logic in both resolveMetadataURL and
validateAbsoluteHTTPURL.
internal/mcp/auth/metadata.go-81-88 (1)

81-88: ⚠️ Potential issue | 🟠 Major

Build the RFC 8414 well-known URL in the correct order.

Per RFC 8414, for issuers with a path component, the metadata endpoint must be https://host/.well-known/oauth-authorization-server/<issuer-path>. The current code at line 85 appends the well-known path after the issuer path, resulting in https://host/<issuer-path>/.well-known/oauth-authorization-server, which will never resolve successfully.

Suggested fix
-	parsed.Path = strings.TrimRight(parsed.Path, "/") + metadataWellKnownPath
+	issuerPath := strings.TrimRight(parsed.Path, "/")
+	parsed.Path = metadataWellKnownPath
+	if issuerPath != "" {
+		parsed.Path += issuerPath
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/mcp/auth/metadata.go` around lines 81 - 88, The code builds the
well-known URL in the wrong order; update the construction so the RFC 8414
well-known segment is placed immediately under the host and the original issuer
path follows it (not vice versa). Concretely, after validating parsed (from
url.Parse(issuer)), set parsed.Path to combine metadataWellKnownPath first and
then the issuer path (trim leading/trailing slashes appropriately to avoid
double slashes), clear parsed.RawQuery and parsed.Fragment, and return
parsed.String(); reference parsed, issuer, and metadataWellKnownPath to locate
the change.
internal/observe/health.go-140-149 (1)

140-149: ⚠️ Potential issue | 🟠 Major

Include failure-health degradation in the top-level status.

collectFailureHealth can mark the failures section as degraded, but the overall Health.Status ignores it. That means the daemon can report top-level "ok" while simultaneously surfacing persisted lifecycle failures.

Suggested fix
-		Status:             observeHealthStatus(persistenceHealth.Status, agentProbeStatus(agentProbes)),
+		Status:             observeHealthStatus(
+			persistenceHealth.Status,
+			failureHealth.Status,
+			agentProbeStatus(agentProbes),
+		),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/observe/health.go` around lines 140 - 149, The top-level
Health.Status ignores degradation reported by collectFailureHealth
(failureHealth), so the daemon can show "ok" despite failures; update the status
computation used when building Health (the call to observeHealthStatus(...)) to
also consider failureHealth.Status (and treat a degraded/failed failureHealth as
degrading the overall status), e.g., compute a combined status from
persistenceHealth.Status, agentProbeStatus(agentProbes) and failureHealth.Status
and pass that into observeHealthStatus or replace the direct call so
Health.Status reflects failureHealth degradations.
internal/cli/config.go-1146-1159 (1)

1146-1159: ⚠️ Potential issue | 🟠 Major

Replace strings.Fields() with shellquote.Split() to properly handle EDITOR/VISUAL values with spaces and quotes.

strings.Fields() splits on any whitespace without respecting shell quoting or escapes. This breaks real-world cases like:

  • EDITOR="/path with spaces/vim" → incorrectly splits into separate arguments
  • EDITOR="vim --option 'value with spaces'" → loses quoted context

The codebase already uses github.com/kballard/go-shellquote extensively for this exact pattern (see internal/acp/client.go and internal/session/manager_hooks.go). Replace with shellquote.Split() to handle POSIX shell word-splitting rules correctly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/config.go` around lines 1146 - 1159, In runConfigEditor replace
strings.Fields(editor) with shellquote.Split(editor) so EDITOR/VISUAL values
respect shell quoting/escapes; update the import to include
github.com/kballard/go-shellquote, change the parts variable assignment to call
shellquote.Split and handle its returned ([]string, error) by returning an error
if split fails, and keep the existing len(parts)==0 check before building
exec.CommandContext(parts[0], append(parts[1:], path)...).
internal/store/globaldb/global_db_mcp_auth.go-32-58 (1)

32-58: ⚠️ Potential issue | 🟠 Major

Persisting raw OAuth tokens in the DB is a credential exposure risk.

access_token and refresh_token are written verbatim into mcp_auth_tokens. Anyone who can read the global DB file gets live bearer/refresh credentials for the remote MCP server. Please move these secrets to an OS keychain or encrypt them before persistence.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/store/globaldb/global_db_mcp_auth.go` around lines 32 - 58, The code
currently persists raw OAuth tokens (normalized.AccessToken,
normalized.RefreshToken) into the mcp_auth_tokens table; instead store only an
encrypted blob or a keychain reference: replace writing
normalized.AccessToken/RefreshToken in the INSERT/ON CONFLICT with either
encrypted values produced by a helper (e.g., EncryptToken(ctx, plaintext) /
DecryptToken(ctx,ciphertext)) or with a generated keychain ID saved via
SaveTokenToKeychain(serverName, token) and persist that ID; update all readers
that load from mcp_auth_tokens to call the corresponding
DecryptToken/GetTokenFromKeychain before returning tokens; add/use a secure root
(environment-provided envelope key or OS keychain APIs) and ensure nullableTime,
store.FormatTimestamp usage remains unchanged while adjusting the parameter
order to match the modified INSERT placeholders.
internal/acp/client.go-239-245 (1)

239-245: ⚠️ Potential issue | 🟠 Major

Cancel the per-process context when registry setup fails.

If Register fails here, the subprocess is stopped, but the procCtx passed into newLocalToolHostFromPolicy stays live. Any tool-host or terminal goroutines bound to that context can outlive the failed start. Call cancelProcess() before returning from this cleanup path.

Suggested fix
 	if err := d.registerAgentProcess(ctx, process); err != nil {
+		cancelProcess()
 		stopCtx, cancelStop := context.WithTimeout(context.Background(), d.stopTimeout)
 		defer cancelStop()
 		if stopErr := handle.Stop(stopCtx); stopErr != nil {
 			return nil, errors.Join(err, fmt.Errorf("acp: cleanup unregistered agent process: %w", stopErr))
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/acp/client.go` around lines 239 - 245, When
registerAgentProcess(ctx, process) fails, the per-process context (procCtx
created for newLocalToolHostFromPolicy) is not canceled and can leak goroutines;
modify the error cleanup path in the block that checks if err :=
d.registerAgentProcess(...) to call cancelProcess() before performing
handle.Stop and returning. Specifically, ensure cancelProcess() is invoked
immediately after detecting the register error (prior to stopCtx/handle.Stop and
prior to returning the error) so any goroutines using procCtx are terminated
when registration fails.
internal/store/globaldb/global_db_automation_scheduler.go-440-452 (1)

440-452: ⚠️ Potential issue | 🟠 Major

Use structured error checking instead of string matching.

Line 442 uses strings.Contains(strings.ToLower(err.Error()), ...) to detect constraint violations, which violates the coding guideline requiring errors.Is() or structured error inspection.

The codebase already uses the correct pattern with modernc.org/sqlite: check for *sqlite.Error using type assertion and inspect the error code (see internal/extension/registry.go:755). Replace the string matching with:

var sqliteErr *sqlite.Error
if errors.As(err, &sqliteErr) && sqliteErr.Code()&0xff == sqlite3.SQLITE_CONSTRAINT_UNIQUE {
    return fmt.Errorf(...)
}

Note: This same pattern should also be applied to internal/store/globaldb/global_db_workspace.go and internal/store/globaldb/global_db_automation.go, which use string matching for similar constraint checks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/store/globaldb/global_db_automation_scheduler.go` around lines 440 -
452, Replace the string-based constraint check in the create automation run
error handling with structured SQLite error inspection: use errors.As to assert
the error to *sqlite.Error (e.g., into a variable sqliteErr) and test
sqliteErr.Code()&0xff == sqlite3.SQLITE_CONSTRAINT_UNIQUE to detect the
unique-constraint-on-fire_id case, then return the same wrapped
automation.ErrScheduledFireAlreadyClaimed; apply the identical pattern wherever
similar string matching is used (notably in global_db_workspace.go and
global_db_automation.go) to consistently replace strings.Contains(err.Error(),
...) with errors.As + sqlite error code checking.

Comment thread internal/cli/mcp_auth.go
Comment thread internal/daemon/daemon.go
Comment thread internal/mcp/auth/pkce.go
Comment thread internal/mcp/auth/service.go
Comment thread internal/memory/catalog.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

🧹 Nitpick comments (6)
internal/session/crash_bundle_test.go (1)

27-29: Use timestamp-derived assertions instead of hardcoded "101"/"202" substrings.

These checks are a bit brittle and less explicit. Derive expected timestamp tokens from first/second so the assertion tracks the actual test inputs.

Suggested refactor
 import (
+	"strconv"
 	"strings"
 	"testing"
 	"time"
@@
-		if !strings.Contains(firstName, "101") || !strings.Contains(secondName, "202") {
+		if !strings.Contains(firstName, strconv.FormatInt(first.UnixNano(), 10)) ||
+			!strings.Contains(secondName, strconv.FormatInt(second.UnixNano(), 10)) {
 			t.Fatalf("crash bundle names = %q, %q; want timestamp suffixes preserved", firstName, secondName)
 		}

As per coding guidelines, "MUST test meaningful business logic, not trivial operations".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/crash_bundle_test.go` around lines 27 - 29, The test
currently asserts hardcoded substrings "101"/"202" in crash bundle file names
(variables firstName and secondName); instead, extract the expected timestamp
tokens from the test inputs (variables first and second) and assert those tokens
are present in firstName and secondName respectively so the assertion reflects
actual input data; locate the assertion block referencing firstName/secondName
and replace the hardcoded checks with checks that derive expected suffixes from
first/second (or their timestamp-formatting logic used elsewhere in the test)
and assert strings.Contains(firstName, expectedFromFirst) and
strings.Contains(secondName, expectedFromSecond).
internal/session/prompt_activity_test.go (1)

214-229: Expand this test to lock in all timeoutStopDeadline() branches.

Line 225 currently validates only the configured positive-grace path. The method also guarantees fallback behavior for nil supervisor and non-positive grace; adding those as table-driven subtests will make regressions much harder.

📌 Suggested refactor (table-driven subtests)
 func TestPromptActivitySupervisorTimeoutStopDeadline(t *testing.T) {
 	t.Parallel()
 
-	t.Run("ShouldUseConfiguredTimeoutCancelGraceForForcedStopDeadline", func(t *testing.T) {
-		t.Parallel()
-
-		supervisor := &promptActivitySupervisor{
-			config: aghconfig.SessionSupervisionConfig{
-				TimeoutCancelGrace: 42 * time.Millisecond,
-			},
-		}
-		if got, want := supervisor.timeoutStopDeadline(), 42*time.Millisecond; got != want {
-			t.Fatalf("timeoutStopDeadline() = %s, want %s", got, want)
-		}
-	})
+	defaultGrace := aghconfig.DefaultSessionSupervisionConfig().TimeoutCancelGrace
+	tests := []struct {
+		name       string
+		supervisor *promptActivitySupervisor
+		want       time.Duration
+	}{
+		{
+			name: "ShouldUseConfiguredTimeoutCancelGraceForForcedStopDeadline",
+			supervisor: &promptActivitySupervisor{
+				config: aghconfig.SessionSupervisionConfig{
+					TimeoutCancelGrace: 42 * time.Millisecond,
+				},
+			},
+			want: 42 * time.Millisecond,
+		},
+		{
+			name:       "ShouldFallbackToDefaultWhenSupervisorIsNil",
+			supervisor: nil,
+			want:       defaultGrace,
+		},
+		{
+			name: "ShouldFallbackToDefaultWhenTimeoutCancelGraceIsNonPositive",
+			supervisor: &promptActivitySupervisor{
+				config: aghconfig.SessionSupervisionConfig{TimeoutCancelGrace: 0},
+			},
+			want: defaultGrace,
+		},
+	}
+
+	for _, tc := range tests {
+		tc := tc
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			if got := tc.supervisor.timeoutStopDeadline(); got != tc.want {
+				t.Fatalf("timeoutStopDeadline() = %s, want %s", got, tc.want)
+			}
+		})
+	}
 }

As per coding guidelines, **/*_test.go: Use table-driven tests with subtests (t.Run) as default pattern for Go tests, and MUST test meaningful business logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/prompt_activity_test.go` around lines 214 - 229, Add
table-driven subtests covering all branches of
promptActivitySupervisor.timeoutStopDeadline(): test a positive
TimeoutCancelGrace (existing case), a zero and a negative TimeoutCancelGrace
(each should fall back to the default grace value), and a nil receiver case
((*promptActivitySupervisor)(nil).timeoutStopDeadline()). Use t.Run for each
row, set up promptActivitySupervisor with
aghconfig.SessionSupervisionConfig{TimeoutCancelGrace: ...} where appropriate,
and assert the returned duration equals the configured value for positive input
and equals the known default (use the same default constant/logic used by
timeoutStopDeadline()) for zero/negative/nil cases. Ensure tests are
table-driven and parallelized as subtests.
internal/session/resume_repair_test.go (1)

137-137: Use a fixed timestamp in this test for determinism.

Using time.Now().UTC() can make future assertions brittle if time-derived formatting/details become part of expectations. A fixed UTC value keeps this test fully reproducible.

💡 Suggested tweak
-			repaired, changed := ClassifyInactiveMetaForRecovery(time.Now().UTC(), meta)
+			fixedNow := time.Date(2026, time.January, 2, 3, 4, 5, 0, time.UTC)
+			repaired, changed := ClassifyInactiveMetaForRecovery(fixedNow, meta)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/resume_repair_test.go` at line 137, The test calls
ClassifyInactiveMetaForRecovery with time.Now().UTC(), which makes the test
non-deterministic; replace that call with a fixed UTC timestamp (e.g. a
time.Date(...) value stored in a local variable like fixedNow) and pass that
fixed value into ClassifyInactiveMetaForRecovery so the test is reproducible and
assertions won't vary by current time.
internal/observe/observer_test.go (1)

93-169: Prefer one table-driven retention test here.

These two cases differ only by config and expected outcomes, so a single subtest table would remove duplication and make future retention branches easier to extend.

As per coding guidelines, "Use table-driven tests with subtests (t.Run) as default pattern for Go tests".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/observe/observer_test.go` around lines 93 - 169, The two tests
TestSweepRetentionUsesConfiguredCutoff and
TestSweepRetentionDisabledKeepsHistory should be merged into a single
table-driven test using subtests: create a slice of cases (name,
RetentionConfig, sessionID, pre-seeded events, expected health fields like
Enabled, RetentionDays, LastSweepStatus, LastCutoffAt, DeletedEventSummaries,
and expected remaining events), loop over cases and call t.Run(case.name, func(t
*testing.T){ ... }), reuse setup code (newHarness,
h.observer.setRetentionHealth(h.observer.initialRetentionHealth()), newSession,
h.observer.OnSessionCreated, h.recordEvent) and call h.observer.SweepRetention
and h.observer.QueryEvents inside each subtest, asserting the case-specific
expectations; reference existing symbols RetentionConfig,
h.observer.SweepRetention, initialRetentionHealth, setRetentionHealth,
newSession, h.recordEvent to locate and adapt the current logic into each
subtest.
internal/daemon/daemon.go (1)

559-563: Make the agent probe interval configurable.

2*time.Second bakes daemon polling behavior into the composition root, so operators and tests cannot tune it without a code change. Please source this from deps.Config.Observability or an option instead of hardcoding it.

As per coding guidelines, Never hardcode configuration — use TOML config or functional options.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/daemon/daemon.go` around lines 559 - 563, The agent probe interval
is hardcoded as 2*time.Second in the observe.WithAgentProbeSource call; make it
configurable by reading a probe interval value from deps.Config.Observability
(or add a new Observability.AgentProbeInterval field) and pass that value
instead of the literal. Update the construction where
observe.WithAgentProbeSource(agentProbeTargetSource(&deps.Config,
deps.AgentCatalog, deps.Logger), 2*time.Second) is called to use the configured
duration (with a sensible default/fallback if unset), and propagate the config
field into any relevant composition or functional option so tests and operators
can tune it without code changes.
internal/memory/store_test.go (1)

1130-1266: Add a cross-workspace history subtest here.

This scenario only ever exercises one workspace in the shared catalog, so it won't fail if History loses the bound workspace default or if scope="" events bleed across workspaces. A second t.Run("Should isolate history by workspace") case would cover the real multi-workspace path these APIs are built around.

As per coding guidelines, **/*_test.go: MUST use t.Run("Should...") pattern for ALL test casesandFocus on critical paths: workflow execution, state management, error handling`.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/memory/store_test.go` around lines 1130 - 1266, The test
TestStoreOperationHistoryFiltersRedactsBoundsAndPersists only exercises one
workspace and can miss cross-workspace bleed; add a t.Run("Should isolate
history by workspace") subtest that creates a second workspace via
NewStore(...).ForWorkspace(anotherRoot), writes at least one ScopeWorkspace and
one global event (use workspaceStore.Write and workspaceStore.logCatalogEvent or
the reopened store), then call History with OperationHistoryQuery scoped to the
first workspace (Workspace: workspaceRoot, Scope: ScopeWorkspace) and assert
results do not include records from the second workspace and vice versa;
reference functions/types to touch: NewStore, ForWorkspace, Write,
logCatalogEvent, History, OperationHistoryQuery, ScopeWorkspace, OperationWrite
to ensure isolation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/acp/client.go`:
- Around line 249-250: Replace the use of context.WithoutCancel (e.g. where
waitCtx := context.WithoutCancel(ctx) and go process.waitForExit(waitCtx)) with
the original caller context or a derived context that preserves deadlines (e.g.
pass ctx directly or use context.WithTimeout(ctx, <reasonable-duration>)) so
registry operations like Checkpoint and Complete aren't made unbounded; update
the same pattern at the other occurrences (the other context.WithoutCancel uses
noted in the comment) and ensure Stop and p.done are not blocked by operations
that lack deadlines.

In `@internal/cli/lifecycle.go`:
- Around line 277-291: The TOON renderer inside the anonymous toon func for
renderToonObject is missing the uninstall-specific fields daemon_stopped and
removed; update the field name slice (currently including
"command","status",...,"purged") to also include "daemon_stopped" and "removed",
and add the corresponding values from the lifecycleRecord into the values slice
(e.g., convert record.DaemonStopped to a string via fmt.Sprintf("%t") and
stringify record.Removed appropriately) so renderToonObject receives the same
uninstall fields that human/JSON outputs expose.
- Around line 143-163: The managed-uninstall flow currently validates
--purge/--force and calls loadRuntimeContext(deps) before checking
detectManagedState, causing managed installs to error on local validations and
runtime failures; change the logic in the uninstall handler to call
detectManagedState() first and if state.Managed is true immediately construct
the lifecycleRecord (using lifecycleRecord, lifecycleStatusDeferred,
managedRecommendation(state.Manager, "uninstall AGH")) and return
writeCommandOutput(cmd, lifecycleBundle("Uninstall", record)) without performing
the --purge validation or calling loadRuntimeContext(deps); only perform the
purge/force check and loadRuntimeContext when state.Managed is false.
- Around line 106-121: The update command currently calls deps.resolveHome()
before checking managed state, causing managed installs to fail if local home is
missing; move the detectManagedState(deps) call and the managed-install
short-circuit (creating lifecycleRecord with Command "update",
Managed/state.Manager, setting Status to lifecycleStatusDeferred, Message and
Recommendation via managedRecommendation) to run before calling
deps.resolveHome(), and only call deps.resolveHome() and set HomeDir on the
lifecycleRecord when state.Managed is false; ensure
writeCommandOutput(lifecycleBundle("Update", record)) is still returned for the
managed path.

In `@internal/cli/mcp_auth.go`:
- Around line 47-55: When mcpauth.NewService(db) fails, don't ignore the
db.Close(ctx) error or return the raw err; capture the close error and return a
wrapped error with context. Replace `_ = db.Close(ctx)` with code that does
`closeErr := db.Close(ctx)` and if closeErr != nil return nil, nil,
fmt.Errorf("mcpauth.NewService failed: %w; db.Close failed: %v", err,
closeErr)`, otherwise return nil, nil, fmt.Errorf("mcpauth.NewService failed:
%w", err). Refer to globaldb.OpenGlobalDB, mcpauth.NewService, db.Close, ctx and
homePaths.DatabaseFile to locate the relevant block.

In `@internal/daemon/daemon_test.go`:
- Around line 2236-2276: Wrap the entire test body of
TestRunShutsDownWhenObserverRetentionStartFails in a t.Run subtest with a
descriptive name starting with "Should..." (e.g., t.Run("Should shutdown when
observer retention start fails", func(t *testing.T) { ... })), ensuring you move
the existing t.Parallel() and all setup/assertions into that subtest block so
the test follows the required t.Run("Should...") pattern.

In `@internal/diagnostics/redact_test.go`:
- Around line 36-40: The loop over maxBytes in the test should be converted into
table-driven subtests that call t.Run for each case so failures are isolated;
replace the for _, maxBytes := range []int{0, -1} loop with a slice of test
cases (e.g., name and maxBytes) and run each case with t.Run("Should ...",
func(t *testing.T) { if got := RedactAndBound("token=super-secret",
tc.maxBytes); got != "" { t.Fatalf(...) } }), ensuring each subtest name follows
the "Should..." pattern and references RedactAndBound so results are checked
per-case.

In `@internal/mcp/auth/service_test.go`:
- Around line 27-84: The test's httptest handler (switch on
metadataWellKnownPath, "/token", "/revoke") and helper writeJSON must not call
t.Fatalf/t.Fatal from handler goroutines; instead create an error channel (e.g.,
errCh := make(chan error, 1) or an errors slice protected by mu) and have
handler code replace each t.Fatalf/t.Fatal and writeJSON-internal test failures
with sending errors to errCh (or return an error value from writeJSON). In
writeJSON change its signature to return error instead of calling t.Fatal*, and
have handlers check that error and send it to errCh; in the main test goroutine
select/receive from errCh after exercising the server and call t.Fatalf/t.Fatal
there if any handler-reported error exists; also stop using t.Fatal* inside
ParseForm error branches and instead send those errors to errCh. This keeps
refreshCalled/revokedToken/mu logic intact but ensures all test failures are
raised from the main test goroutine.

In `@internal/mcp/auth/service.go`:
- Around line 219-233: The current flow returns early on discoverMetadata or
s.revoke errors which prevents s.store.DeleteMCPAuthToken from running; change
the logic so metadata discovery and revoke attempts (discoverMetadata and
s.revoke) are best-effort: capture/log any metaErr or revokeErr but do NOT
return immediately, ensure s.store.DeleteMCPAuthToken(ctx, cfg.ServerName)
always runs (e.g., by restructuring the if-block or using a defer/cleanup path),
and then return statusFromToken(cfg, nil, s.now()), nil; keep unique calls
discoverMetadata, s.revoke, s.store.DeleteMCPAuthToken, and statusFromToken so
reviewers can find the changes.
- Around line 27-49: NewService currently assigns http.DefaultClient (which has
no timeout) causing network calls to potentially hang; change the constructor to
set service.client to a new http.Client with a sensible timeout (e.g., 10s) as
the default unless a ServiceOption overrides it: remove reliance on
http.DefaultClient and the dead-code fallback in discoverMetadata, initialize
service.client = &http.Client{Timeout: 10 * time.Second} in NewService (or
provide a ServiceOption to configure the timeout) so Login/Refresh/Logout
metadata discovery, code exchange, refresh and revocation requests cannot block
indefinitely.

In `@internal/memory/store.go`:
- Around line 349-356: The issue is that when opts.Scope is empty but
opts.Workspace resolves to a concrete workspace, you currently log records with
Scope="" which is treated as global; update the code that constructs the
OperationRecord for calls to s.logCatalogEvent (e.g., the OperationSearch and
OperationReindex records) to replace an empty normalized scope with a
workspace-specific scope: compute scopeNorm := scope.Normalize(); if scopeNorm
== "" && workspaceRoot != "" { scopeNorm = workspaceRoot }; then set
OperationRecord.Scope = scopeNorm so events are persisted with a concrete,
workspace-bound scope (apply the same change to the other logging site around
lines 394-404).
- Around line 487-490: The History method currently does manual normalization
(setting normalized.Scope, normalized.Workspace, normalized.Operation) but omits
the store-bound workspace behavior; replace that manual handling by calling the
existing normalizeScopeAndWorkspace helper so the store's workspace is applied
when query.Workspace is empty. Specifically, in History use
normalizeScopeAndWorkspace(&normalized, s.workspaceDir) (or the helper's actual
signature) to set Scope and Workspace, then still call Operation.Normalize() on
normalized.Operation if needed, removing the direct canonicalWorkspaceRoot and
Scope.Normalize calls in this block.

In `@internal/observe/health.go`:
- Around line 220-239: health.Recent is keeping the first 10 entries returned by
ListSessions instead of the 10 newest by UpdatedAt, so sort health.Recent by
UpdatedAt descending before you trim it: after populating health.Recent (but
before the len check/trim) use sort.Slice to order entries by UpdatedAt (newest
first), then slice to the first 10 entries; ensure you still preserve the
redaction fields and the existing Total/ByKind/Status logic (referencing
health.Recent, UpdatedAt, and the ListSessions population loop) so the "recent"
section reliably contains the newest failures.

In `@internal/observe/observer_test.go`:
- Around line 556-617: The test relies on Failures.Recent being sorted by
UpdatedAt but currently registers the newer "sess-crash" first so the test can
pass even if no sorting occurs; update the test setup in observer_test.go to
register the older session before the newer one (i.e., call
h.registry.RegisterSession for "sess-protocol" before "sess-crash") or, better,
scramble insertion order deliberately and then assert that observer.Health()
returns Failures.Recent sorted descending by UpdatedAt (check
h.observer.Health(), health.Failures.Recent, and the SessionID/FailureKind
ordering) so the test actually verifies the sorting behavior rather than
registry insertion order.

In `@internal/retry/retry_test.go`:
- Around line 159-164: The tests currently only assert that Do(...) returns a
non-nil error; update them to assert specific error content using
ErrorContains/ErrorAs (or the testing helper used in the repo) so regressions
are caught: for the call Do(nilRetryContext(), Policy{}, nil, func(...){...})
assert the error contains the expected "nil context" message or sentinel error,
and for Do(context.Background(), Policy{}, nil, nil) assert the error contains
the expected "nil operation" message (and make the same stronger assertion for
the similar checks at lines 184-186). Locate the assertions around the Do
function calls, nilRetryContext, and Policy in retry_test.go and replace the
generic non-nil checks with precise ErrorContains/ErrorAs assertions referencing
the expected error text or sentinel error values.
- Around line 248-274: The three test helper functions sequenceRand,
equalDurations, and nilRetryContext should be converted to accept a *testing.T
parameter and must call t.Helper() at the top so test failures point to the
caller; update their signatures to sequenceRand(t *testing.T, values
...float64), equalDurations(t *testing.T, left, right []time.Duration), and
nilRetryContext(t *testing.T) with t.Helper() as the first statement in each,
and then update all test callers to pass the *testing.T value.

---

Nitpick comments:
In `@internal/daemon/daemon.go`:
- Around line 559-563: The agent probe interval is hardcoded as 2*time.Second in
the observe.WithAgentProbeSource call; make it configurable by reading a probe
interval value from deps.Config.Observability (or add a new
Observability.AgentProbeInterval field) and pass that value instead of the
literal. Update the construction where
observe.WithAgentProbeSource(agentProbeTargetSource(&deps.Config,
deps.AgentCatalog, deps.Logger), 2*time.Second) is called to use the configured
duration (with a sensible default/fallback if unset), and propagate the config
field into any relevant composition or functional option so tests and operators
can tune it without code changes.

In `@internal/memory/store_test.go`:
- Around line 1130-1266: The test
TestStoreOperationHistoryFiltersRedactsBoundsAndPersists only exercises one
workspace and can miss cross-workspace bleed; add a t.Run("Should isolate
history by workspace") subtest that creates a second workspace via
NewStore(...).ForWorkspace(anotherRoot), writes at least one ScopeWorkspace and
one global event (use workspaceStore.Write and workspaceStore.logCatalogEvent or
the reopened store), then call History with OperationHistoryQuery scoped to the
first workspace (Workspace: workspaceRoot, Scope: ScopeWorkspace) and assert
results do not include records from the second workspace and vice versa;
reference functions/types to touch: NewStore, ForWorkspace, Write,
logCatalogEvent, History, OperationHistoryQuery, ScopeWorkspace, OperationWrite
to ensure isolation.

In `@internal/observe/observer_test.go`:
- Around line 93-169: The two tests TestSweepRetentionUsesConfiguredCutoff and
TestSweepRetentionDisabledKeepsHistory should be merged into a single
table-driven test using subtests: create a slice of cases (name,
RetentionConfig, sessionID, pre-seeded events, expected health fields like
Enabled, RetentionDays, LastSweepStatus, LastCutoffAt, DeletedEventSummaries,
and expected remaining events), loop over cases and call t.Run(case.name, func(t
*testing.T){ ... }), reuse setup code (newHarness,
h.observer.setRetentionHealth(h.observer.initialRetentionHealth()), newSession,
h.observer.OnSessionCreated, h.recordEvent) and call h.observer.SweepRetention
and h.observer.QueryEvents inside each subtest, asserting the case-specific
expectations; reference existing symbols RetentionConfig,
h.observer.SweepRetention, initialRetentionHealth, setRetentionHealth,
newSession, h.recordEvent to locate and adapt the current logic into each
subtest.

In `@internal/session/crash_bundle_test.go`:
- Around line 27-29: The test currently asserts hardcoded substrings "101"/"202"
in crash bundle file names (variables firstName and secondName); instead,
extract the expected timestamp tokens from the test inputs (variables first and
second) and assert those tokens are present in firstName and secondName
respectively so the assertion reflects actual input data; locate the assertion
block referencing firstName/secondName and replace the hardcoded checks with
checks that derive expected suffixes from first/second (or their
timestamp-formatting logic used elsewhere in the test) and assert
strings.Contains(firstName, expectedFromFirst) and strings.Contains(secondName,
expectedFromSecond).

In `@internal/session/prompt_activity_test.go`:
- Around line 214-229: Add table-driven subtests covering all branches of
promptActivitySupervisor.timeoutStopDeadline(): test a positive
TimeoutCancelGrace (existing case), a zero and a negative TimeoutCancelGrace
(each should fall back to the default grace value), and a nil receiver case
((*promptActivitySupervisor)(nil).timeoutStopDeadline()). Use t.Run for each
row, set up promptActivitySupervisor with
aghconfig.SessionSupervisionConfig{TimeoutCancelGrace: ...} where appropriate,
and assert the returned duration equals the configured value for positive input
and equals the known default (use the same default constant/logic used by
timeoutStopDeadline()) for zero/negative/nil cases. Ensure tests are
table-driven and parallelized as subtests.

In `@internal/session/resume_repair_test.go`:
- Line 137: The test calls ClassifyInactiveMetaForRecovery with
time.Now().UTC(), which makes the test non-deterministic; replace that call with
a fixed UTC timestamp (e.g. a time.Date(...) value stored in a local variable
like fixedNow) and pass that fixed value into ClassifyInactiveMetaForRecovery so
the test is reproducible and assertions won't vary by current time.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 863b5804-ea55-47b2-88fd-28508e405ed8

📥 Commits

Reviewing files that changed from the base of the PR and between 3354029 and ce2b921.

⛔ Files ignored due to path filters (32)
  • .compozy/tasks/hermes/reviews-001/_meta.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_001.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_002.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_003.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_004.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_005.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_006.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_007.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_008.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_009.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_010.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_011.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_012.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_013.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_014.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_015.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_016.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_017.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_018.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_019.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_020.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_021.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_022.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_023.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_024.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_025.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_026.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_027.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_028.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_029.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_030.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-001/issue_031.md is excluded by !**/*.md
📒 Files selected for processing (46)
  • internal/acp/client.go
  • internal/acp/client_test.go
  • internal/acp/types.go
  • internal/api/core/automation_test.go
  • internal/bridgesdk/errors.go
  • internal/bridgesdk/errors_test.go
  • internal/cli/config.go
  • internal/cli/lifecycle.go
  • internal/cli/lifecycle_test.go
  • internal/cli/mcp_auth.go
  • internal/cli/mcp_auth_test.go
  • internal/config/release_config_test.go
  • internal/daemon/agent_probes.go
  • internal/daemon/agent_probes_test.go
  • internal/daemon/daemon.go
  • internal/daemon/daemon_test.go
  • internal/diagnostics/redact.go
  • internal/diagnostics/redact_test.go
  • internal/environment/daytona/provider.go
  • internal/environment/daytona/provider_test.go
  • internal/environment/daytona/tool_host.go
  • internal/mcp/auth/metadata.go
  • internal/mcp/auth/metadata_test.go
  • internal/mcp/auth/pkce.go
  • internal/mcp/auth/pkce_test.go
  • internal/mcp/auth/service.go
  • internal/mcp/auth/service_test.go
  • internal/memory/catalog.go
  • internal/memory/store.go
  • internal/memory/store_test.go
  • internal/observe/health.go
  • internal/observe/observer_test.go
  • internal/procutil/process_group_windows.go
  • internal/retry/retry.go
  • internal/retry/retry_test.go
  • internal/session/crash_bundle.go
  • internal/session/crash_bundle_test.go
  • internal/session/liveness.go
  • internal/session/prompt_activity.go
  • internal/session/prompt_activity_test.go
  • internal/session/resume_repair_test.go
  • internal/skills/provenance.go
  • internal/skills/provenance_test.go
  • internal/store/globaldb/global_db_automation_scheduler.go
  • internal/store/globaldb/global_db_mcp_auth.go
  • internal/store/globaldb/global_db_mcp_auth_test.go
✅ Files skipped from review due to trivial changes (2)
  • internal/daemon/agent_probes.go
  • internal/cli/config.go
🚧 Files skipped from review as they are similar to previous changes (10)
  • internal/session/prompt_activity.go
  • internal/procutil/process_group_windows.go
  • internal/session/liveness.go
  • internal/api/core/automation_test.go
  • internal/cli/mcp_auth_test.go
  • internal/diagnostics/redact.go
  • internal/config/release_config_test.go
  • internal/bridgesdk/errors_test.go
  • internal/session/crash_bundle.go
  • internal/cli/lifecycle_test.go

Comment thread internal/acp/client.go Outdated
Comment thread internal/cli/lifecycle.go Outdated
Comment thread internal/cli/lifecycle.go Outdated
Comment thread internal/cli/lifecycle.go
Comment thread internal/cli/mcp_auth.go
Comment thread internal/memory/store.go
Comment thread internal/observe/health.go Outdated
Comment thread internal/observe/observer_test.go
Comment thread internal/retry/retry_test.go Outdated
Comment thread internal/retry/retry_test.go Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
internal/cli/mcp_auth.go (1)

290-295: Ignored error on stderr write.

Per the coding guidelines, errors should not be ignored with _. While writing to stderr for terminal output rarely fails and is non-critical, adding a brief comment would satisfy the "written justification" requirement.

Suggested justification comment
+	// Best-effort stderr output; failure is non-critical for CLI UX.
 	_, _ = fmt.Fprintf(
 		cmd.ErrOrStderr(),
 		"Open this URL to authenticate %s:\n%s\n",
 		cfg.ServerName,
 		state.AuthorizationURL,
 	)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/mcp_auth.go` around lines 290 - 295, The stderr write currently
ignores the returned error from fmt.Fprintf; update the call in the block that
writes the auth URL (the fmt.Fprintf call using cmd.ErrOrStderr(),
cfg.ServerName and state.AuthorizationURL) so the error is either captured and
handled (e.g., assign to err and log or return it) or, if you intentionally want
to ignore it, remove the blank assignment and add a one-line justification
comment directly above the call explaining why the error is safe to ignore
(e.g., non-critical terminal output). Ensure the change references the
fmt.Fprintf invocation and cmd.ErrOrStderr() so reviewers can see the handling
or justification.
internal/acp/client.go (1)

891-898: Consider using a consistent logger reference.

Line 896 uses slog.Default() while Stop at line 670 uses d.logger. Since waitForExit runs detached from the driver, consider storing the logger reference on AgentProcess during construction for consistent log routing.

♻️ Proposed approach

Add a logger field to AgentProcess and set it in newAgentProcess:

 type AgentProcess struct {
+    logger *slog.Logger
     // ... other fields
 }

Then in waitForExit:

-       slog.Default().Warn("acp: complete process record", "pid", p.PID, "error", err)
+       p.logger.Warn("acp: complete process record", "pid", p.PID, "error", err)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/acp/client.go` around lines 891 - 898, The code in waitForExit uses
slog.Default() for logging while other methods (like Stop) use the driver's
logger; add a logger field to AgentProcess, set it in newAgentProcess (copy
d.logger into the new AgentProcess instance), and replace slog.Default() calls
in waitForExit (the block handling p.processRecord completion) with p.logger so
all logs (e.g., the warning about Complete failing for p.PID) use the same
logger reference.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/cli/lifecycle.go`:
- Around line 119-121: The command-phase branches return raw errors from
deps.resolveHome and deps.loadRuntime; wrap these errors with context using
fmt.Errorf so callers know which phase failed (e.g., fmt.Errorf("resolving home
for update: %w", err) for the resolveHome call and fmt.Errorf("loading runtime
for uninstall: %w", err) for the loadRuntime call). Update the return statements
around calls to resolveHome and loadRuntime in lifecycle.go to wrap the
underlying err with descriptive context mentioning the operation and command
(update/uninstall) and import fmt if necessary.
- Around line 205-220: Wrap and annotate errors returned from helper calls so
failures carry context: when checking daemonInfo (the call returning info,
running, err) replace the bare "return false, err" with a wrapped error using
fmt.Errorf("daemonInfo: %w", err); likewise wrap the error returned from
waitForDaemonStop (the call waitForDaemonStop(ctx, deps, runtime, info)) as
"return false, fmt.Errorf(\"waitForDaemonStop: %w\", err)"; ensure any other
direct returns of dependency/helper errors in this block (e.g., after
signalProcess where you propagate non-ESRCH/ErrProcessDone errors) are returned
with contextual wrapping like fmt.Errorf("signalProcess: %w", err) so callers
get explicit context for uninstall failures.
- Around line 184-187: The purge branch currently calls
os.RemoveAll(runtime.HomePaths.HomeDir) without verifying the resolved path; add
a safety check before that call to reject unsafe targets (root, empty, ".", "/",
parent dirs, or paths outside the current user's home or a dedicated config
dir). Implement by resolving and cleaning the target
(filepath.Abs/filepath.Clean on runtime.HomePaths.HomeDir), obtain the current
user home (os.UserHomeDir()) or the dedicated safe parent (e.g.,
runtime.HomePaths.ConfigDir), and ensure the cleaned absolute target has the
safe parent as a prefix and is not equal to "/" or "."; if the invariant fails,
return a descriptive error instead of removing; only call os.RemoveAll when the
check passes (replace the direct RemoveAll call in the purge branch).

---

Nitpick comments:
In `@internal/acp/client.go`:
- Around line 891-898: The code in waitForExit uses slog.Default() for logging
while other methods (like Stop) use the driver's logger; add a logger field to
AgentProcess, set it in newAgentProcess (copy d.logger into the new AgentProcess
instance), and replace slog.Default() calls in waitForExit (the block handling
p.processRecord completion) with p.logger so all logs (e.g., the warning about
Complete failing for p.PID) use the same logger reference.

In `@internal/cli/mcp_auth.go`:
- Around line 290-295: The stderr write currently ignores the returned error
from fmt.Fprintf; update the call in the block that writes the auth URL (the
fmt.Fprintf call using cmd.ErrOrStderr(), cfg.ServerName and
state.AuthorizationURL) so the error is either captured and handled (e.g.,
assign to err and log or return it) or, if you intentionally want to ignore it,
remove the blank assignment and add a one-line justification comment directly
above the call explaining why the error is safe to ignore (e.g., non-critical
terminal output). Ensure the change references the fmt.Fprintf invocation and
cmd.ErrOrStderr() so reviewers can see the handling or justification.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 07a53835-b5d9-4222-a8c7-556dca1985cb

📥 Commits

Reviewing files that changed from the base of the PR and between ce2b921 and 9739091.

⛔ Files ignored due to path filters (63)
  • .agents/skills/favicon-gen/SKILL.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/favicon-gen/assets/favicon-svg-circle.svg is excluded by !**/*.svg, !.agents/**
  • .agents/skills/favicon-gen/assets/favicon-svg-shield.svg is excluded by !**/*.svg, !.agents/**
  • .agents/skills/favicon-gen/assets/favicon-svg-square.svg is excluded by !**/*.svg, !.agents/**
  • .agents/skills/favicon-gen/assets/manifest.webmanifest is excluded by !.agents/**
  • .agents/skills/favicon-gen/references/extraction-methods.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/favicon-gen/references/format-guide.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/favicon-gen/references/monogram-patterns.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/favicon-gen/references/shape-templates.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/SKILL.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/async-patterns.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/bundling.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/data-patterns.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/debug-tricks.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/directives.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/error-handling.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/file-conventions.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/font.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/functions.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/hydration-error.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/image.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/metadata.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/parallel-routes.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/route-handlers.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/rsc-boundaries.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/runtime-selection.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/scripts.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/self-hosting.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/next-best-practices/suspense-boundaries.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/seo-audit/SKILL.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/seo-audit/evals/evals.json is excluded by !**/*.json, !.agents/**
  • .agents/skills/seo-audit/references/ai-writing-detection.md is excluded by !**/*.md, !.agents/**
  • .agents/skills/seo-audit/references/international-seo.md is excluded by !**/*.md, !.agents/**
  • .claude/agents/designer.md is excluded by !**/*.md, !.claude/**
  • .codex/plans/2026-04-20-prompt-stream-stall.md is excluded by !**/*.md
  • .codex/plans/2026-04-20-session-chat-production-hardening.md is excluded by !**/*.md
  • .codex/plans/2026-04-25-site-hardening.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/_meta.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_001.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_002.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_003.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_004.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_005.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_006.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_007.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_008.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_009.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_010.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_011.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_012.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_013.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_014.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_015.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_016.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_017.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_018.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_019.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_020.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_021.md is excluded by !**/*.md
  • .compozy/tasks/hermes/reviews-002/issue_022.md is excluded by !**/*.md
  • AGENTS.md is excluded by !**/*.md
  • CLAUDE.md is excluded by !**/*.md
  • DESIGN.md is excluded by !**/*.md
📒 Files selected for processing (37)
  • internal/acp/client.go
  • internal/acp/client_test.go
  • internal/cli/lifecycle.go
  • internal/cli/lifecycle_test.go
  • internal/cli/mcp_auth.go
  • internal/config/config.go
  • internal/config/config_test.go
  • internal/config/merge.go
  • internal/daemon/daemon.go
  • internal/daemon/daemon_test.go
  • internal/diagnostics/redact_test.go
  • internal/mcp/auth/service.go
  • internal/mcp/auth/service_test.go
  • internal/memory/store.go
  • internal/memory/store_test.go
  • internal/observe/health.go
  • internal/observe/observer_test.go
  • internal/retry/retry_test.go
  • internal/session/crash_bundle_test.go
  • internal/session/prompt_activity_test.go
  • internal/session/resume_repair_test.go
  • packages/site/app/(home)/layout.tsx
  • packages/site/app/error.tsx
  • packages/site/app/global.css
  • packages/site/app/layout.tsx
  • packages/site/app/not-found.tsx
  • packages/site/app/opengraph-image.tsx
  • packages/site/app/protocol/[[...slug]]/page.tsx
  • packages/site/app/protocol/layout.tsx
  • packages/site/app/robots.ts
  • packages/site/app/runtime/[[...slug]]/page.tsx
  • packages/site/app/runtime/layout.tsx
  • packages/site/app/sitemap.ts
  • packages/site/components/landing/final-cta.tsx
  • packages/site/components/landing/primitives/code-block.test.tsx
  • packages/site/components/landing/primitives/code-block.tsx
  • packages/site/components/landing/primitives/cta-button.tsx
✅ Files skipped from review due to trivial changes (1)
  • internal/cli/lifecycle_test.go

Comment thread internal/cli/lifecycle.go
Comment on lines +119 to +121
homePaths, err := deps.resolveHome()
if err != nil {
return err
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Wrap these command-phase errors.

These branches still return bare errors, so callers lose whether the failure came from resolving home during update or loading runtime during uninstall.

Suggested fix
 			homePaths, err := deps.resolveHome()
 			if err != nil {
-				return err
+				return fmt.Errorf("cli: resolve AGH home for update: %w", err)
 			}
@@
 			runtime, err := loadRuntimeContext(deps)
 			if err != nil {
-				return err
+				return fmt.Errorf("cli: load runtime context for uninstall: %w", err)
 			}

As per coding guidelines **/*.go: Explicit error returns with wrapped context using fmt.Errorf("context: %w", err).

Also applies to: 160-162

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/lifecycle.go` around lines 119 - 121, The command-phase branches
return raw errors from deps.resolveHome and deps.loadRuntime; wrap these errors
with context using fmt.Errorf so callers know which phase failed (e.g.,
fmt.Errorf("resolving home for update: %w", err) for the resolveHome call and
fmt.Errorf("loading runtime for uninstall: %w", err) for the loadRuntime call).
Update the return statements around calls to resolveHome and loadRuntime in
lifecycle.go to wrap the underlying err with descriptive context mentioning the
operation and command (update/uninstall) and import fmt if necessary.

Comment thread internal/cli/lifecycle.go
Comment on lines +184 to +187
if purge {
if err := os.RemoveAll(runtime.HomePaths.HomeDir); err != nil {
return fmt.Errorf("cli: purge AGH home %q: %w", runtime.HomePaths.HomeDir, err)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Definitions involved in purge path resolution:"
rg -n -C4 'func\s+(loadRuntimeContext|ResolveHome|ResolveHomePaths|ResolveHomePathsFrom)\b' internal

echo
echo "Delete sites and any nearby safety guards:"
rg -n -C3 'RemoveAll\(|filepath\.Clean|EvalSymlinks|IsAbs|unsafe|refus|root|HomeDir' internal

Repository: compozy/agh

Length of output: 50368


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== resolveAbsoluteDir implementation in home.go ==="
sed -n '1,150p' internal/config/home.go | tail -60

echo
echo "=== Full ResolveHomePathsFrom function ==="
sed -n '92,130p' internal/config/home.go

Repository: compozy/agh

Length of output: 3507


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Full context around line 184-187 in lifecycle.go ==="
sed -n '175,200p' internal/cli/lifecycle.go

Repository: compozy/agh

Length of output: 1020


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Full ResolvePath implementation ==="
grep -n "func ResolvePath" internal/config/home.go -A 30

Repository: compozy/agh

Length of output: 1030


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check if there are any validations against unsafe paths like '/', '.', etc ==="
rg -n "HomeDir.*==|==.*HomeDir|forbidden|unsafe|reject.*root|IsAbs.*check" internal/config internal/cli

Repository: compozy/agh

Length of output: 544


Add validation to prevent purge from deleting unsafe paths.

Line 185 recursively deletes runtime.HomePaths.HomeDir without verification. The path resolution in internal/config/home.go (via ResolvePathfilepath.Abs) accepts any path, including /, ., or other system directories. If AGH_HOME is set to an unsafe value, agh uninstall --purge --force can wipe unrelated data. Add an explicit invariant check before calling os.RemoveAll to reject paths that are not under a safe parent directory (e.g., user home or a dedicated config directory).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/lifecycle.go` around lines 184 - 187, The purge branch currently
calls os.RemoveAll(runtime.HomePaths.HomeDir) without verifying the resolved
path; add a safety check before that call to reject unsafe targets (root, empty,
".", "/", parent dirs, or paths outside the current user's home or a dedicated
config dir). Implement by resolving and cleaning the target
(filepath.Abs/filepath.Clean on runtime.HomePaths.HomeDir), obtain the current
user home (os.UserHomeDir()) or the dedicated safe parent (e.g.,
runtime.HomePaths.ConfigDir), and ensure the cleaned absolute target has the
safe parent as a prefix and is not equal to "/" or "."; if the invariant fails,
return a descriptive error instead of removing; only call os.RemoveAll when the
check passes (replace the direct RemoveAll call in the purge branch).

Comment thread internal/cli/lifecycle.go
Comment on lines +205 to +220
info, running, err := daemonInfo(runtime.HomePaths, deps)
if err != nil {
return false, err
}
if !running {
return false, nil
}
if err := deps.signalProcess(info.PID, syscall.SIGTERM); err != nil {
if errors.Is(err, os.ErrProcessDone) || errors.Is(err, syscall.ESRCH) {
return true, nil
}
return false, fmt.Errorf("cli: stop daemon for uninstall: %w", err)
}
if _, err := waitForDaemonStop(ctx, deps, runtime, info); err != nil {
return false, err
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Preserve helper context on uninstall failures.

Line 207, Line 219, and Line 234 still bubble dependency/helper errors up untouched, which makes daemon-stop and artifact-removal failures harder to triage.

Suggested fix
 func stopDaemonForUninstall(ctx context.Context, deps commandDeps, runtime *runtimeContext) (bool, error) {
 	info, running, err := daemonInfo(runtime.HomePaths, deps)
 	if err != nil {
-		return false, err
+		return false, fmt.Errorf("cli: inspect daemon state for uninstall: %w", err)
 	}
@@
 	if _, err := waitForDaemonStop(ctx, deps, runtime, info); err != nil {
-		return false, err
+		return false, fmt.Errorf("cli: wait for daemon shutdown during uninstall: %w", err)
 	}
 	return true, nil
 }
@@
 	for _, path := range candidates {
 		deleted, err := removeFileIfExists(path)
 		if err != nil {
-			return nil, err
+			return nil, fmt.Errorf("cli: remove runtime artifacts: %w", err)
 		}

As per coding guidelines **/*.go: Explicit error returns with wrapped context using fmt.Errorf("context: %w", err).

Also applies to: 232-234

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/lifecycle.go` around lines 205 - 220, Wrap and annotate errors
returned from helper calls so failures carry context: when checking daemonInfo
(the call returning info, running, err) replace the bare "return false, err"
with a wrapped error using fmt.Errorf("daemonInfo: %w", err); likewise wrap the
error returned from waitForDaemonStop (the call waitForDaemonStop(ctx, deps,
runtime, info)) as "return false, fmt.Errorf(\"waitForDaemonStop: %w\", err)";
ensure any other direct returns of dependency/helper errors in this block (e.g.,
after signalProcess where you propagate non-ESRCH/ErrProcessDone errors) are
returned with contextual wrapping like fmt.Errorf("signalProcess: %w", err) so
callers get explicit context for uninstall failures.

pedronauck added a commit that referenced this pull request May 26, 2026
## Release v0.0.1

This PR prepares the release of version v0.0.1.

### Changelog

## 0.0.1 - 2026-05-26



### Other Changes

- Lessons learned



### ♻️ Refactoring

- Project structure (#7)
- Kb improvements (#12)
- Rename spaces to channels (#17)
- Add extensions gaps (#21)
- Improve tool calls ui (#22)
- Remove web app header
- Module improvements (#29)
- Memory improvements (#35)
- Storybook for web and ui (#38)
- Enable AGH network by default for new installs (#57)
- Hermes adjustments (#69)
- Badges design (#84)
- Storybook scenario and logos gallery
- Migrate typescript tests (#114)
- Internal go packages (#120)
- Ui patterns (#127)
- Improve e2e tests (#130)
- Ui redesign
- Workspace isolation across runtime surfaces (#145)
- Prod ready applies (#162)
- Tool card ui (#164)
- Alpha on logo
- Prod ready features (#167)
- Thread sheet (#202)



### 🎉 Features

- Implement config foundation packages
- Implement sqlite store package
- Add ACP client package
- Add session lifecycle manager
- Implement observe package
- Add daemon composition root
- Add uds api server
- Implement cli package
- Add http api server
- Add system design
- Add foundation types, schemas, and layout shell for web client
- Add daemon health polling and agent sidebar systems for web client
- Add session system CRUD, streaming core, and session store for web
client
- Add chat view, messages, and composer tests for web client
- Add tool cards and renderers for web client
- Add file-backed memory store core
- Scaffold memory session seams
- Add memory dream consolidation service
- Wire memory assembler into daemon
- Add memory api and cli
- New skills system (#1)
- Add workspace entity (#5)
- Add new skill capabilities (#8)
- Web ui v2 (#9)
- Improve hooks system (#10)
- Session resilience (#11)
- Add extensability (#13)
- Add automation (#16)
- Add channels (#14)
- Add network implementation (#15)
- Add network, bridges and automations web pages (#18)
- Ext registry (#20)
- Add core tasks (#19)
- Bridge adapters (#23)
- Add site (#26)
- Add ext refac and sandbox (#25)
- Settings ui (#37)
- Tasks ui (#36)
- Harness improvements (#44)
- Agent capabilities (#49)
- Redesign ui (#48)
- Unify capability (#53)
- Redesign network workspace (#59)
- Add task deletion and split session delete from stop (#58)
- Session provider selection (#60)
- Production grade adjustments (#66)
- Autonomous system (#75)
- Add agent session route (#80)
- Tools registry (#85)
- Agents soul (#88)
- Add network threads (#105)
- Orchestration improvements (#106)
- Memory v2 (#108)
- Agent categories (#113)
- Providers model (#118)
- Add canonical AGH bundled skill (#143)
- Onboarding and improvements (#198)
- Onboarding and improvements (#201)



### 🐛 Bug Fixes

- Review round
- Review rounds
- Resolve memory extensibility review batch
- Embed web into daemon
- Defaults agents
- Acp integration (#4)
- Lint errors
- Prd folder
- Remove orphan web actions and dead surfaces (#55)
- Qa testing and fixes (#73)
- New review rounds (#82)
- Security audit (#90)
- Release qa round (#95)
- Add missing tools (#141)
- New qa round (#147)
- Advanced qa round (#149)
- Homebrew tap
- Final review round (#151)
- Daemon healthy
- Reasoning models (#158)
- Lint errors (#160)
- Review round (#168)
- Release adjustments (#171)
- Stabilize release ci fixtures
- Stabilize release integration gate
- Stabilize release verify gates
- Stabilize release integration flows
- Stabilize release verify gates
- Stabilize main verify shutdown
- Ignore stale acpmock cancel
- Marketplace search focus and filtering (#193)
- Website video
- Workspace command select



### 📚 Documentation

- Update agents.md
- Update prd
- Update skills
- Update compozy tasks
- Update compozy
- Update compozy
- Add new skills
- Archive prd
- Update prds
- Update rfc
- Update prds
- Update prds
- Add automation prd
- Channels prd
- Update prd
- Update prd
- New prds
- Archive prds
- Bridges adapters prd
- Sandbox prd
- Update
- Archive prd
- Update
- Add new prd
- New design
- Update prd
- Archive prds
- Update prds
- Tasks-ui prd tasks
- Update prd
- Update design docs
- Agent capabilities prd
- Improve site docs
- Remove old design references
- Udpate
- Autonomous prd
- Update skills
- Blog design
- Agent sould prd
- Final qa plan
- Update
- Remove codex ledgers from gitignore
- Remove not needed files
- Udpate ledger
- Update cy-codex-loop skill
- Orchestration improves prd
- Update prds
- Orch improvs prd
- Memv2 prd
- Providers model prd
- Update refacs prd
- New design proposal
- Update rules
- Update skills
- New blog posts (#173)
- Format docs
- Remove old design files
- Remove old
- Skeeper update



### 📦 Build System

- Initial structure
- Commitlint
- Frontend base structure
- Update vscode settings
- Add subagents
- Coderabbit
- Prd and tooling
- Bun lock
- Lint tooling
- Copy.md and tooling adjusts
- Add repoclone rc
- Upgrade skeeper to v0.2.0
- Update go.mod
- Adopt task artifacts into skeeper
- Sync codex plans with skeeper
- Skeeper lock
- Skeeper lock
- New skills
- Skeeper lock
- Skeeper lock
- Skeeper lock
- Update deps and go
- Regenerate daytona sidecar assets for go 1.26.3
- Fix cliff
- Ignore docs on fmt
- Build web assets before goreleaser
- Extend release dry-run timeout



### 🔧 CI/CD

- Lint errors
- Fint release pr
- Fix goreleaser



### 🧪 Testing

- Add e2e tests (#27)
- Qa rounds (#78)
- Improve test suite (#138)
- Harden daemon-served restart reloads
- Harden daemon-served readiness waits
- Stabilize dashboard focus assertion
- Stabilize release integration gates
- Stabilize release e2e markers
- Stabilize release e2e flows

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This was referenced May 26, 2026
pedronauck added a commit that referenced this pull request May 26, 2026
## Release v0.0.1

This PR prepares the release of version v0.0.1.

### Changelog

## 0.0.1 - 2026-05-26



### Other Changes

- Lessons learned



### ♻️ Refactoring

- Project structure (#7)
- Kb improvements (#12)
- Rename spaces to channels (#17)
- Add extensions gaps (#21)
- Improve tool calls ui (#22)
- Remove web app header
- Module improvements (#29)
- Memory improvements (#35)
- Storybook for web and ui (#38)
- Enable AGH network by default for new installs (#57)
- Hermes adjustments (#69)
- Badges design (#84)
- Storybook scenario and logos gallery
- Migrate typescript tests (#114)
- Internal go packages (#120)
- Ui patterns (#127)
- Improve e2e tests (#130)
- Ui redesign
- Workspace isolation across runtime surfaces (#145)
- Prod ready applies (#162)
- Tool card ui (#164)
- Alpha on logo
- Prod ready features (#167)
- Thread sheet (#202)



### 🎉 Features

- Implement config foundation packages
- Implement sqlite store package
- Add ACP client package
- Add session lifecycle manager
- Implement observe package
- Add daemon composition root
- Add uds api server
- Implement cli package
- Add http api server
- Add system design
- Add foundation types, schemas, and layout shell for web client
- Add daemon health polling and agent sidebar systems for web client
- Add session system CRUD, streaming core, and session store for web
client
- Add chat view, messages, and composer tests for web client
- Add tool cards and renderers for web client
- Add file-backed memory store core
- Scaffold memory session seams
- Add memory dream consolidation service
- Wire memory assembler into daemon
- Add memory api and cli
- New skills system (#1)
- Add workspace entity (#5)
- Add new skill capabilities (#8)
- Web ui v2 (#9)
- Improve hooks system (#10)
- Session resilience (#11)
- Add extensability (#13)
- Add automation (#16)
- Add channels (#14)
- Add network implementation (#15)
- Add network, bridges and automations web pages (#18)
- Ext registry (#20)
- Add core tasks (#19)
- Bridge adapters (#23)
- Add site (#26)
- Add ext refac and sandbox (#25)
- Settings ui (#37)
- Tasks ui (#36)
- Harness improvements (#44)
- Agent capabilities (#49)
- Redesign ui (#48)
- Unify capability (#53)
- Redesign network workspace (#59)
- Add task deletion and split session delete from stop (#58)
- Session provider selection (#60)
- Production grade adjustments (#66)
- Autonomous system (#75)
- Add agent session route (#80)
- Tools registry (#85)
- Agents soul (#88)
- Add network threads (#105)
- Orchestration improvements (#106)
- Memory v2 (#108)
- Agent categories (#113)
- Providers model (#118)
- Add canonical AGH bundled skill (#143)
- Onboarding and improvements (#198)
- Onboarding and improvements (#201)



### 🐛 Bug Fixes

- Review round
- Review rounds
- Resolve memory extensibility review batch
- Embed web into daemon
- Defaults agents
- Acp integration (#4)
- Lint errors
- Prd folder
- Remove orphan web actions and dead surfaces (#55)
- Qa testing and fixes (#73)
- New review rounds (#82)
- Security audit (#90)
- Release qa round (#95)
- Add missing tools (#141)
- New qa round (#147)
- Advanced qa round (#149)
- Homebrew tap
- Final review round (#151)
- Daemon healthy
- Reasoning models (#158)
- Lint errors (#160)
- Review round (#168)
- Release adjustments (#171)
- Stabilize release ci fixtures
- Stabilize release integration gate
- Stabilize release verify gates
- Stabilize release integration flows
- Stabilize release verify gates
- Stabilize main verify shutdown
- Ignore stale acpmock cancel
- Marketplace search focus and filtering (#193)
- Website video
- Workspace command select



### 📚 Documentation

- Update agents.md
- Update prd
- Update skills
- Update compozy tasks
- Update compozy
- Update compozy
- Add new skills
- Archive prd
- Update prds
- Update rfc
- Update prds
- Update prds
- Add automation prd
- Channels prd
- Update prd
- Update prd
- New prds
- Archive prds
- Bridges adapters prd
- Sandbox prd
- Update
- Archive prd
- Update
- Add new prd
- New design
- Update prd
- Archive prds
- Update prds
- Tasks-ui prd tasks
- Update prd
- Update design docs
- Agent capabilities prd
- Improve site docs
- Remove old design references
- Udpate
- Autonomous prd
- Update skills
- Blog design
- Agent sould prd
- Final qa plan
- Update
- Remove codex ledgers from gitignore
- Remove not needed files
- Udpate ledger
- Update cy-codex-loop skill
- Orchestration improves prd
- Update prds
- Orch improvs prd
- Memv2 prd
- Providers model prd
- Update refacs prd
- New design proposal
- Update rules
- Update skills
- New blog posts (#173)
- Format docs
- Remove old design files
- Remove old
- Skeeper update



### 📦 Build System

- Initial structure
- Commitlint
- Frontend base structure
- Update vscode settings
- Add subagents
- Coderabbit
- Prd and tooling
- Bun lock
- Lint tooling
- Copy.md and tooling adjusts
- Add repoclone rc
- Upgrade skeeper to v0.2.0
- Update go.mod
- Adopt task artifacts into skeeper
- Sync codex plans with skeeper
- Skeeper lock
- Skeeper lock
- New skills
- Skeeper lock
- Skeeper lock
- Skeeper lock
- Update deps and go
- Regenerate daytona sidecar assets for go 1.26.3
- Fix cliff
- Ignore docs on fmt
- Build web assets before goreleaser
- Extend release dry-run timeout



### 🔧 CI/CD

- Lint errors
- Fint release pr
- Fix goreleaser
- Fix release



### 🧪 Testing

- Add e2e tests (#27)
- Qa rounds (#78)
- Improve test suite (#138)
- Harden daemon-served restart reloads
- Harden daemon-served readiness waits
- Stabilize dashboard focus assertion
- Stabilize release integration gates
- Stabilize release e2e markers
- Stabilize release e2e flows

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
pedronauck added a commit that referenced this pull request May 26, 2026
## Release v0.0.2

This PR prepares the release of version v0.0.2.

### Changelog

## 0.0.2 - 2026-05-26



### Other Changes

- Lessons learned



### ♻️ Refactoring

- Project structure (#7)
- Kb improvements (#12)
- Rename spaces to channels (#17)
- Add extensions gaps (#21)
- Improve tool calls ui (#22)
- Remove web app header
- Module improvements (#29)
- Memory improvements (#35)
- Storybook for web and ui (#38)
- Enable AGH network by default for new installs (#57)
- Hermes adjustments (#69)
- Badges design (#84)
- Storybook scenario and logos gallery
- Migrate typescript tests (#114)
- Internal go packages (#120)
- Ui patterns (#127)
- Improve e2e tests (#130)
- Ui redesign
- Workspace isolation across runtime surfaces (#145)
- Prod ready applies (#162)
- Tool card ui (#164)
- Alpha on logo
- Prod ready features (#167)
- Thread sheet (#202)



### 🎉 Features

- Implement config foundation packages
- Implement sqlite store package
- Add ACP client package
- Add session lifecycle manager
- Implement observe package
- Add daemon composition root
- Add uds api server
- Implement cli package
- Add http api server
- Add system design
- Add foundation types, schemas, and layout shell for web client
- Add daemon health polling and agent sidebar systems for web client
- Add session system CRUD, streaming core, and session store for web
client
- Add chat view, messages, and composer tests for web client
- Add tool cards and renderers for web client
- Add file-backed memory store core
- Scaffold memory session seams
- Add memory dream consolidation service
- Wire memory assembler into daemon
- Add memory api and cli
- New skills system (#1)
- Add workspace entity (#5)
- Add new skill capabilities (#8)
- Web ui v2 (#9)
- Improve hooks system (#10)
- Session resilience (#11)
- Add extensability (#13)
- Add automation (#16)
- Add channels (#14)
- Add network implementation (#15)
- Add network, bridges and automations web pages (#18)
- Ext registry (#20)
- Add core tasks (#19)
- Bridge adapters (#23)
- Add site (#26)
- Add ext refac and sandbox (#25)
- Settings ui (#37)
- Tasks ui (#36)
- Harness improvements (#44)
- Agent capabilities (#49)
- Redesign ui (#48)
- Unify capability (#53)
- Redesign network workspace (#59)
- Add task deletion and split session delete from stop (#58)
- Session provider selection (#60)
- Production grade adjustments (#66)
- Autonomous system (#75)
- Add agent session route (#80)
- Tools registry (#85)
- Agents soul (#88)
- Add network threads (#105)
- Orchestration improvements (#106)
- Memory v2 (#108)
- Agent categories (#113)
- Providers model (#118)
- Add canonical AGH bundled skill (#143)
- Onboarding and improvements (#198)
- Onboarding and improvements (#201)



### 🐛 Bug Fixes

- Review round
- Review rounds
- Resolve memory extensibility review batch
- Embed web into daemon
- Defaults agents
- Acp integration (#4)
- Lint errors
- Prd folder
- Remove orphan web actions and dead surfaces (#55)
- Qa testing and fixes (#73)
- New review rounds (#82)
- Security audit (#90)
- Release qa round (#95)
- Add missing tools (#141)
- New qa round (#147)
- Advanced qa round (#149)
- Homebrew tap
- Final review round (#151)
- Daemon healthy
- Reasoning models (#158)
- Lint errors (#160)
- Review round (#168)
- Release adjustments (#171)
- Stabilize release ci fixtures
- Stabilize release integration gate
- Stabilize release verify gates
- Stabilize release integration flows
- Stabilize release verify gates
- Stabilize main verify shutdown
- Ignore stale acpmock cancel
- Marketplace search focus and filtering (#193)
- Website video
- Workspace command select



### 📚 Documentation

- Update agents.md
- Update prd
- Update skills
- Update compozy tasks
- Update compozy
- Update compozy
- Add new skills
- Archive prd
- Update prds
- Update rfc
- Update prds
- Update prds
- Add automation prd
- Channels prd
- Update prd
- Update prd
- New prds
- Archive prds
- Bridges adapters prd
- Sandbox prd
- Update
- Archive prd
- Update
- Add new prd
- New design
- Update prd
- Archive prds
- Update prds
- Tasks-ui prd tasks
- Update prd
- Update design docs
- Agent capabilities prd
- Improve site docs
- Remove old design references
- Udpate
- Autonomous prd
- Update skills
- Blog design
- Agent sould prd
- Final qa plan
- Update
- Remove codex ledgers from gitignore
- Remove not needed files
- Udpate ledger
- Update cy-codex-loop skill
- Orchestration improves prd
- Update prds
- Orch improvs prd
- Memv2 prd
- Providers model prd
- Update refacs prd
- New design proposal
- Update rules
- Update skills
- New blog posts (#173)
- Format docs
- Remove old design files
- Remove old
- Skeeper update



### 📦 Build System

- Initial structure
- Commitlint
- Frontend base structure
- Update vscode settings
- Add subagents
- Coderabbit
- Prd and tooling
- Bun lock
- Lint tooling
- Copy.md and tooling adjusts
- Add repoclone rc
- Upgrade skeeper to v0.2.0
- Update go.mod
- Adopt task artifacts into skeeper
- Sync codex plans with skeeper
- Skeeper lock
- Skeeper lock
- New skills
- Skeeper lock
- Skeeper lock
- Skeeper lock
- Update deps and go
- Regenerate daytona sidecar assets for go 1.26.3
- Fix cliff
- Ignore docs on fmt
- Build web assets before goreleaser
- Extend release dry-run timeout



### 🔧 CI/CD

- Lint errors
- Fint release pr
- Fix goreleaser
- Fix release
- Fix release process



### 🧪 Testing

- Add e2e tests (#27)
- Qa rounds (#78)
- Improve test suite (#138)
- Harden daemon-served restart reloads
- Harden daemon-served readiness waits
- Stabilize dashboard focus assertion
- Stabilize release integration gates
- Stabilize release e2e markers
- Stabilize release e2e flows
- Improve suite speed

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
pedronauck added a commit that referenced this pull request May 27, 2026
## Release v0.0.2

This PR prepares the release of version v0.0.2.

### Changelog

## 0.0.2 - 2026-05-26



### Other Changes

- Lessons learned



### ♻️ Refactoring

- Project structure (#7)
- Kb improvements (#12)
- Rename spaces to channels (#17)
- Add extensions gaps (#21)
- Improve tool calls ui (#22)
- Remove web app header
- Module improvements (#29)
- Memory improvements (#35)
- Storybook for web and ui (#38)
- Enable AGH network by default for new installs (#57)
- Hermes adjustments (#69)
- Badges design (#84)
- Storybook scenario and logos gallery
- Migrate typescript tests (#114)
- Internal go packages (#120)
- Ui patterns (#127)
- Improve e2e tests (#130)
- Ui redesign
- Workspace isolation across runtime surfaces (#145)
- Prod ready applies (#162)
- Tool card ui (#164)
- Alpha on logo
- Prod ready features (#167)
- Thread sheet (#202)



### 🎉 Features

- Implement config foundation packages
- Implement sqlite store package
- Add ACP client package
- Add session lifecycle manager
- Implement observe package
- Add daemon composition root
- Add uds api server
- Implement cli package
- Add http api server
- Add system design
- Add foundation types, schemas, and layout shell for web client
- Add daemon health polling and agent sidebar systems for web client
- Add session system CRUD, streaming core, and session store for web
client
- Add chat view, messages, and composer tests for web client
- Add tool cards and renderers for web client
- Add file-backed memory store core
- Scaffold memory session seams
- Add memory dream consolidation service
- Wire memory assembler into daemon
- Add memory api and cli
- New skills system (#1)
- Add workspace entity (#5)
- Add new skill capabilities (#8)
- Web ui v2 (#9)
- Improve hooks system (#10)
- Session resilience (#11)
- Add extensability (#13)
- Add automation (#16)
- Add channels (#14)
- Add network implementation (#15)
- Add network, bridges and automations web pages (#18)
- Ext registry (#20)
- Add core tasks (#19)
- Bridge adapters (#23)
- Add site (#26)
- Add ext refac and sandbox (#25)
- Settings ui (#37)
- Tasks ui (#36)
- Harness improvements (#44)
- Agent capabilities (#49)
- Redesign ui (#48)
- Unify capability (#53)
- Redesign network workspace (#59)
- Add task deletion and split session delete from stop (#58)
- Session provider selection (#60)
- Production grade adjustments (#66)
- Autonomous system (#75)
- Add agent session route (#80)
- Tools registry (#85)
- Agents soul (#88)
- Add network threads (#105)
- Orchestration improvements (#106)
- Memory v2 (#108)
- Agent categories (#113)
- Providers model (#118)
- Add canonical AGH bundled skill (#143)
- Onboarding and improvements (#198)
- Onboarding and improvements (#201)



### 🐛 Bug Fixes

- Review round
- Review rounds
- Resolve memory extensibility review batch
- Embed web into daemon
- Defaults agents
- Acp integration (#4)
- Lint errors
- Prd folder
- Remove orphan web actions and dead surfaces (#55)
- Qa testing and fixes (#73)
- New review rounds (#82)
- Security audit (#90)
- Release qa round (#95)
- Add missing tools (#141)
- New qa round (#147)
- Advanced qa round (#149)
- Homebrew tap
- Final review round (#151)
- Daemon healthy
- Reasoning models (#158)
- Lint errors (#160)
- Review round (#168)
- Release adjustments (#171)
- Stabilize release ci fixtures
- Stabilize release integration gate
- Stabilize release verify gates
- Stabilize release integration flows
- Stabilize release verify gates
- Stabilize main verify shutdown
- Ignore stale acpmock cancel
- Marketplace search focus and filtering (#193)
- Website video
- Workspace command select



### 📚 Documentation

- Update agents.md
- Update prd
- Update skills
- Update compozy tasks
- Update compozy
- Update compozy
- Add new skills
- Archive prd
- Update prds
- Update rfc
- Update prds
- Update prds
- Add automation prd
- Channels prd
- Update prd
- Update prd
- New prds
- Archive prds
- Bridges adapters prd
- Sandbox prd
- Update
- Archive prd
- Update
- Add new prd
- New design
- Update prd
- Archive prds
- Update prds
- Tasks-ui prd tasks
- Update prd
- Update design docs
- Agent capabilities prd
- Improve site docs
- Remove old design references
- Udpate
- Autonomous prd
- Update skills
- Blog design
- Agent sould prd
- Final qa plan
- Update
- Remove codex ledgers from gitignore
- Remove not needed files
- Udpate ledger
- Update cy-codex-loop skill
- Orchestration improves prd
- Update prds
- Orch improvs prd
- Memv2 prd
- Providers model prd
- Update refacs prd
- New design proposal
- Update rules
- Update skills
- New blog posts (#173)
- Format docs
- Remove old design files
- Remove old
- Skeeper update



### 📦 Build System

- Initial structure
- Commitlint
- Frontend base structure
- Update vscode settings
- Add subagents
- Coderabbit
- Prd and tooling
- Bun lock
- Lint tooling
- Copy.md and tooling adjusts
- Add repoclone rc
- Upgrade skeeper to v0.2.0
- Update go.mod
- Adopt task artifacts into skeeper
- Sync codex plans with skeeper
- Skeeper lock
- Skeeper lock
- New skills
- Skeeper lock
- Skeeper lock
- Skeeper lock
- Update deps and go
- Regenerate daytona sidecar assets for go 1.26.3
- Fix cliff
- Ignore docs on fmt
- Build web assets before goreleaser
- Extend release dry-run timeout



### 🔧 CI/CD

- Lint errors
- Fint release pr
- Fix goreleaser
- Fix release
- Fix release process
- Fix release sync
- Decouple release dry-run npm auth
- Persist web assets git auth



### 🧪 Testing

- Add e2e tests (#27)
- Qa rounds (#78)
- Improve test suite (#138)
- Harden daemon-served restart reloads
- Harden daemon-served readiness waits
- Stabilize dashboard focus assertion
- Stabilize release integration gates
- Stabilize release e2e markers
- Stabilize release e2e flows
- Improve suite speed


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated web assets dependency to a newer version for improved
stability and performance.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/compozy/agh/pull/211?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
pedronauck added a commit that referenced this pull request May 27, 2026
## Release v0.0.2

This PR prepares the release of version v0.0.2.

### Changelog

## 0.0.2 - 2026-05-27



### Other Changes

- Lessons learned



### ♻️ Refactoring

- Project structure (#7)
- Kb improvements (#12)
- Rename spaces to channels (#17)
- Add extensions gaps (#21)
- Improve tool calls ui (#22)
- Remove web app header
- Module improvements (#29)
- Memory improvements (#35)
- Storybook for web and ui (#38)
- Enable AGH network by default for new installs (#57)
- Hermes adjustments (#69)
- Badges design (#84)
- Storybook scenario and logos gallery
- Migrate typescript tests (#114)
- Internal go packages (#120)
- Ui patterns (#127)
- Improve e2e tests (#130)
- Ui redesign
- Workspace isolation across runtime surfaces (#145)
- Prod ready applies (#162)
- Tool card ui (#164)
- Alpha on logo
- Prod ready features (#167)
- Thread sheet (#202)



### 🎉 Features

- Implement config foundation packages
- Implement sqlite store package
- Add ACP client package
- Add session lifecycle manager
- Implement observe package
- Add daemon composition root
- Add uds api server
- Implement cli package
- Add http api server
- Add system design
- Add foundation types, schemas, and layout shell for web client
- Add daemon health polling and agent sidebar systems for web client
- Add session system CRUD, streaming core, and session store for web
client
- Add chat view, messages, and composer tests for web client
- Add tool cards and renderers for web client
- Add file-backed memory store core
- Scaffold memory session seams
- Add memory dream consolidation service
- Wire memory assembler into daemon
- Add memory api and cli
- New skills system (#1)
- Add workspace entity (#5)
- Add new skill capabilities (#8)
- Web ui v2 (#9)
- Improve hooks system (#10)
- Session resilience (#11)
- Add extensability (#13)
- Add automation (#16)
- Add channels (#14)
- Add network implementation (#15)
- Add network, bridges and automations web pages (#18)
- Ext registry (#20)
- Add core tasks (#19)
- Bridge adapters (#23)
- Add site (#26)
- Add ext refac and sandbox (#25)
- Settings ui (#37)
- Tasks ui (#36)
- Harness improvements (#44)
- Agent capabilities (#49)
- Redesign ui (#48)
- Unify capability (#53)
- Redesign network workspace (#59)
- Add task deletion and split session delete from stop (#58)
- Session provider selection (#60)
- Production grade adjustments (#66)
- Autonomous system (#75)
- Add agent session route (#80)
- Tools registry (#85)
- Agents soul (#88)
- Add network threads (#105)
- Orchestration improvements (#106)
- Memory v2 (#108)
- Agent categories (#113)
- Providers model (#118)
- Add canonical AGH bundled skill (#143)
- Onboarding and improvements (#198)
- Onboarding and improvements (#201)



### 🐛 Bug Fixes

- Review round
- Review rounds
- Resolve memory extensibility review batch
- Embed web into daemon
- Defaults agents
- Acp integration (#4)
- Lint errors
- Prd folder
- Remove orphan web actions and dead surfaces (#55)
- Qa testing and fixes (#73)
- New review rounds (#82)
- Security audit (#90)
- Release qa round (#95)
- Add missing tools (#141)
- New qa round (#147)
- Advanced qa round (#149)
- Homebrew tap
- Final review round (#151)
- Daemon healthy
- Reasoning models (#158)
- Lint errors (#160)
- Review round (#168)
- Release adjustments (#171)
- Stabilize release ci fixtures
- Stabilize release integration gate
- Stabilize release verify gates
- Stabilize release integration flows
- Stabilize release verify gates
- Stabilize main verify shutdown
- Ignore stale acpmock cancel
- Marketplace search focus and filtering (#193)
- Website video
- Workspace command select



### 📚 Documentation

- Update agents.md
- Update prd
- Update skills
- Update compozy tasks
- Update compozy
- Update compozy
- Add new skills
- Archive prd
- Update prds
- Update rfc
- Update prds
- Update prds
- Add automation prd
- Channels prd
- Update prd
- Update prd
- New prds
- Archive prds
- Bridges adapters prd
- Sandbox prd
- Update
- Archive prd
- Update
- Add new prd
- New design
- Update prd
- Archive prds
- Update prds
- Tasks-ui prd tasks
- Update prd
- Update design docs
- Agent capabilities prd
- Improve site docs
- Remove old design references
- Udpate
- Autonomous prd
- Update skills
- Blog design
- Agent sould prd
- Final qa plan
- Update
- Remove codex ledgers from gitignore
- Remove not needed files
- Udpate ledger
- Update cy-codex-loop skill
- Orchestration improves prd
- Update prds
- Orch improvs prd
- Memv2 prd
- Providers model prd
- Update refacs prd
- New design proposal
- Update rules
- Update skills
- New blog posts (#173)
- Format docs
- Remove old design files
- Remove old
- Skeeper update



### 📦 Build System

- Initial structure
- Commitlint
- Frontend base structure
- Update vscode settings
- Add subagents
- Coderabbit
- Prd and tooling
- Bun lock
- Lint tooling
- Copy.md and tooling adjusts
- Add repoclone rc
- Upgrade skeeper to v0.2.0
- Update go.mod
- Adopt task artifacts into skeeper
- Sync codex plans with skeeper
- Skeeper lock
- Skeeper lock
- New skills
- Skeeper lock
- Skeeper lock
- Skeeper lock
- Update deps and go
- Regenerate daytona sidecar assets for go 1.26.3
- Fix cliff
- Ignore docs on fmt
- Build web assets before goreleaser
- Extend release dry-run timeout
- Fix release dry-run token contract



### 🔧 CI/CD

- Lint errors
- Fint release pr
- Fix goreleaser
- Fix release
- Fix release process
- Fix release sync
- Decouple release dry-run npm auth
- Persist web assets git auth
- Require npm auth before release merge



### 🧪 Testing

- Add e2e tests (#27)
- Qa rounds (#78)
- Improve test suite (#138)
- Harden daemon-served restart reloads
- Harden daemon-served readiness waits
- Stabilize dashboard focus assertion
- Stabilize release integration gates
- Stabilize release e2e markers
- Stabilize release e2e flows
- Improve suite speed


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
  * Updated dependencies to latest versions.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/compozy/agh/pull/214?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant