Skip to content

refactor: project structure#7

Merged
pedronauck merged 4 commits into
mainfrom
pn/refactoring
Apr 7, 2026
Merged

refactor: project structure#7
pedronauck merged 4 commits into
mainfrom
pn/refactoring

Conversation

@pedronauck
Copy link
Copy Markdown
Member

@pedronauck pedronauck commented Apr 7, 2026

Summary by CodeRabbit

  • New Features

    • Unified HTTP API with consistent endpoints across transports
    • Shared contract for standardized request/response payloads
    • Expanded session lifecycle: create, resume, stop, prompt, and permission approval flows
    • Workspace CRUD and resolve endpoints
    • Background memory consolidation/runtime for automated “dream” sessions
  • Bug Fixes

    • More consistent HTTP status codes and error responses
    • Fixed edge cases in session, workspace, and streaming flows
  • Improvements

    • Standardized API payload shapes and streaming (SSE) behavior
    • Better observability and health endpoints

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

coderabbitai Bot commented Apr 7, 2026

Caution

Review failed

Pull request was closed or merged during review

Walkthrough

Introduces a shared API contract and core HTTP handler layer, migrates transport handlers to delegate to core, refactors session lifecycle and prompt/permission flows, adds consolidation/dream runtime and daemon boot logic, and introduces multiple utility packages and test helpers. Changes are primarily API, handler, session, memory, daemon, CLI, and tests.

Changes

Cohort / File(s) Summary
ACP
internal/acp/handlers.go, internal/acp/rawjson.go, internal/acp/handlers_test.go, internal/acp/client_test.go, internal/acp/client_integration_test.go
Centralized permission event emission via emitPermissionEvent, replaced local raw-copy with CloneRawMessage, and updated tests to use testutil.Context(t).
API Contract & Core
internal/api/contract/contract.go, internal/api/contract/contract_test.go, internal/api/core/...
Added canonical contract DTOs and core package: conversion helpers, interfaces, error mapping, SSE utilities, parsers, payloads, BaseHandlers implementation (sessions/agents/observe/memory/workspaces/daemon), and extensive tests.
HTTP & UDS Transport
internal/api/httpapi/..., internal/api/udsapi/...
Transport layers refactored to delegate to core.BaseHandlers; route registration updated; added/adjusted handlers (approveSession, promptSession), unified error handling to core.RespondError, and updated many tests and stubs to core interfaces.
API Test Utilities
internal/api/testutil/apitest.go, internal/api/testutil/apitest_test.go
New shared API test stubs (StubSessionManager, StubObserver, StubWorkspaceService) and HTTP/SSE test helpers (SSE parsing, request helpers, home-path helpers).
Session Manager
internal/session/manager.go, internal/session/manager_lifecycle.go, internal/session/manager_prompt.go, internal/session/manager_helpers.go, internal/session/manager_workspace.go, tests...
Reorganized session lifecycle: extracted Create/Stop/Resume/Prompt/ApprovePermission implementations into focused files, added lifecycle helpers (activate/watch, prompt pumping, workspace resolution), added lifecycle context option, and switched to sessiondb.OpenSessionDB.
Memory & Consolidation
internal/memory/consolidation/runtime.go, internal/memory/..., tests...
New consolidation runtime and session spawner for dream runs, gated scheduling, workspace resolution, and integration tests; replaced frontmatter and atomic write logic to use dedicated packages; process-alive checks now use procutil.
Daemon & Orphans
internal/daemon/boot.go, internal/daemon/boundary.go, internal/daemon/orphan.go, internal/daemon/notifier.go, internal/daemon/daemon.go, tests...
Adds daemon boot sequence, import-boundary verifier, orphan process cleanup, notifier fan-out; refactors daemon wiring to use core interfaces and consolidation runtime; many integration/test updates.
Observability
internal/observe/*.go, tests...
Narrowed Registry interface, switched DB opener to globaldb.OpenGlobalDB, improved active agent counting, and updated tests to testutil.Context.
Frontmatter & Config
internal/frontmatter/frontmatter.go, internal/config/agent.go, internal/config/home.go, tests...
New frontmatter splitter/decoder and mapped sentinel errors; agent frontmatter parsing now uses frontmatter package; added ResolvePath and ResolveUserAgentsSkillsDir.
Process/File Utilities
internal/procutil/*, internal/fileutil/*, internal/filesnap/*, tests...
New cross-platform process utilities (procutil), atomic file write with dir-sync (fileutil), and filesystem snapshot utilities (filesnap) with tests and platform-specific implementations.
CLI
internal/cli/*
CLI code updated to alias shared contract types, replaced rendering with generic listBundle, delegated process utilities to procutil, adjusted daemon status construction, and added extensive tests; contexts in tests use testutil.Context(t).
Various Tests & Test Utilities
multiple internal/.../*_test.go and new internal/testutil usage
Widespread test updates to use shared test utilities, rename stub fields to exported *Fn forms, and align tests with new core interfaces and behavior.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant HTTP as HTTP Server
    participant Core as core.BaseHandlers
    participant Sessions as SessionManager
    participant DB as Session DB
    participant Driver as ACP Driver

    Client->>HTTP: POST /api/sessions
    HTTP->>Core: CreateSession(c)
    Core->>Sessions: Create(ctx, opts)
    Sessions->>DB: Open session DB / write metadata
    Sessions->>Driver: Start process
    Driver-->>Sessions: Process handle
    Sessions-->>Core: created session
    Core-->>Client: 201 Created (SessionPayload)

    Client->>HTTP: POST /api/sessions/{id}/prompt
    HTTP->>Core: StreamSession(c)
    Core->>Sessions: Prompt(ctx, id, message)
    Sessions->>Driver: Prompt(ctx, req)
    Driver-->>Sessions: <-chan AgentEvent
    loop stream
      Sessions->>DB: Record Event
      Sessions-->>Core: event
      Core->>Core: PrepareSSE/WriteSSE
      Core-->>Client: SSE frame
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pn/refactoring

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

Note

Due to the large number of review comments, Critical, Major 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 (2)
internal/api/httpapi/httpapi_integration_test.go (1)

1007-1012: ⚠️ Potential issue | 🟠 Major

Fix stale stop-session status expectation in helper.

Line 1008 still expects http.StatusOK, but stop-session handlers now return http.StatusNoContent. This can make integration flows fail even when behavior is correct.

🔧 Proposed fix
 func stopIntegrationSession(t *testing.T, runtime integrationRuntime, sessionID string) {
 	t.Helper()

 	resp := mustHTTPRequest(t, runtime.client, http.MethodDelete, mustURL(runtime.host, runtime.port, "/api/sessions/"+sessionID), nil, nil)
-	if resp.StatusCode != http.StatusOK {
+	if resp.StatusCode != http.StatusNoContent {
 		body, _ := io.ReadAll(resp.Body)
 		_ = resp.Body.Close()
-		t.Fatalf("stop status = %d, want %d; body=%s", resp.StatusCode, http.StatusOK, string(body))
+		t.Fatalf("stop status = %d, want %d; body=%s", resp.StatusCode, http.StatusNoContent, string(body))
 	}
 	_ = resp.Body.Close()
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/httpapi/httpapi_integration_test.go` around lines 1007 - 1012,
The helper currently asserts stop-session DELETE responses against
http.StatusOK; update the assertion to expect http.StatusNoContent instead
(change the comparison from http.StatusOK to http.StatusNoContent and adjust the
failure message accordingly) in the test code that calls mustHTTPRequest for
DELETE "/api/sessions/"+sessionID (the block using resp := mustHTTPRequest(...),
resp.StatusCode check, and t.Fatalf).
internal/cli/client.go (1)

463-465: ⚠️ Potential issue | 🟡 Minor

Avoid context.Background() fallback in production code.

Creating a fallback context with context.Background() when ctx is nil violates the coding guideline requiring callers to provide a proper context. This masks bugs where callers forget to pass context and prevents proper cancellation/timeout propagation.

Proposed fix: require non-nil context
 func (c *unixSocketClient) doRequest(ctx context.Context, method string, path string, query url.Values, requestBody any, lastEventID string) (*http.Response, error) {
-	if ctx == nil {
-		ctx = context.Background()
-	}
+	if ctx == nil {
+		return nil, errors.New("cli: context is required")
+	}
 
 	target := baseURL + path

Alternatively, if maintaining backward compatibility is essential, document this behavior and consider logging a warning.

As per coding guidelines: "Use context.Context as first argument to functions crossing runtime boundaries — 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/cli/client.go` around lines 463 - 465, The current nil-check that
assigns ctx = context.Background() masks caller errors; instead remove the
fallback and enforce a non-nil context by returning an error (or panic) when ctx
== nil (replace the context.Background() assignment with something like "return
fmt.Errorf(\"nil context passed to <functionName>\")" or appropriate error
handling), and update callers to pass a valid context; if backward compatibility
is required, log a clear warning when ctx == nil before returning the error.
Ensure you modify the block that currently checks "if ctx == nil { ctx =
context.Background() }" and reference the variable "ctx" and the function where
this check lives.
🟡 Minor comments (11)
internal/api/httpapi/memory.go-1-1 (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Remove empty package declaration files from httpapi and udsapi packages.

These 8 files contain only package declarations with no implementation:

  • internal/api/httpapi/{memory.go, observe.go, agents.go, stream.go, daemon.go}
  • internal/api/udsapi/{daemon.go, observe.go, stream.go, payloads.go}

All handler functionality (ListAgents, GetAgent, ObserveEvents, StreamObserveEvents, ListMemory, etc.) is already centralized in internal/api/core/handlers.go and wired into both transports via server.go (httpapi) and routes.go (udsapi). These empty files serve no purpose and should be deleted to reduce maintenance overhead.

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

In `@internal/api/httpapi/memory.go` at line 1, Delete the eight no-op files that
contain only package declarations to reduce dead code: in package httpapi remove
memory.go, observe.go, agents.go, stream.go, daemon.go; in package udsapi remove
daemon.go, observe.go, stream.go, payloads.go. Ensure you only remove files that
are truly empty (no exported symbols or init logic), run the build/tests, and
confirm handler functionality remains provided by internal/api/core/handlers.go
and wired via server.go (httpapi) and routes.go (udsapi).
internal/api/udsapi/agents.go-1-1 (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Remove empty agents.go file or implement its intended functionality.

This file contains only a package declaration with no code, functions, or types. The file is not referenced anywhere in the codebase and serves no purpose. Either remove this file or add the implementation it was scaffolded for.

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

In `@internal/api/udsapi/agents.go` at line 1, This file only contains "package
udsapi" and should be removed if unused; otherwise implement the intended agents
API inside package udsapi by adding concrete symbols that other code expects
(for example define an exported type Agent and functions such as NewAgent,
RegisterAgent, and ListAgents or GetAgents) so the package is non-empty and
provides the required functionality; choose removal if nothing depends on
package udsapi or implement the minimal Agent struct and API methods (Agent,
NewAgent, RegisterAgent, ListAgents) to satisfy compilation and future usage.
internal/api/httpapi/daemon.go-1-1 (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Remove unused package scaffolding file.

daemon.go contains only a package declaration and is not referenced anywhere in the codebase. Delete this file along with agents.go, which has the same issue.

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

In `@internal/api/httpapi/daemon.go` at line 1, Delete the unused scaffolding
files that only declare the httpapi package: remove daemon.go and agents.go from
the repository; ensure there are no imports or references to package httpapi
remaining and run a build/test to confirm nothing else depends on those files
(the unique identifiers are the files named daemon.go and agents.go and the
package declaration "package httpapi").
internal/procutil/procutil_test.go-40-53 (1)

40-53: ⚠️ Potential issue | 🟡 Minor

Use errors.Is() to verify the specific error in the missing-process case.

The first test (non-positive PID) correctly rejects the call, but the second test only checks that Signal(999999, 0) returns some error—not that it's the missing-process error. Since Signal wraps the underlying syscall.Kill error with %w (line 26 of procutil.go), the missing-process case should assert:

if err := Signal(999999, syscall.Signal(0)); !errors.Is(err, syscall.ESRCH) {
    t.Fatalf("Signal(missing pid, 0) error = %v, want ESRCH", err)
}

This locks down that the specific error is "no such process," not another failure mode. Per guidelines: use errors.Is() and errors.As() for error matching.

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

In `@internal/procutil/procutil_test.go` around lines 40 - 53, Update the
TestSignalReturnsErrorForMissingProcess test to assert the specific "no such
process" error using errors.Is rather than just checking non-nil; call
Signal(999999, syscall.Signal(0)) and verify errors.Is(err, syscall.ESRCH)
(since Signal wraps syscall.Kill with %w), failing the test with a clear message
if the check is false; this ensures the test verifies the exact missing-process
error from Signal.
internal/acp/handlers_test.go-317-323 (1)

317-323: ⚠️ Potential issue | 🟡 Minor

Use t.Run("Should ...") naming for subtests.

Please rename these subtest names to the required Should ... style for test policy consistency.

As per coding guidelines, 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/acp/handlers_test.go` around lines 317 - 323, The subtests in the
tests slice use short names like "interactive pending" and "auto allow once";
rename each test case name to the required "Should ..." style (e.g., "Should
handle interactive pending", "Should allow once automatically", "Should reject
once on timeout") so that t.Run(tt.name, ...) follows the mandated pattern;
update the entries in the tests array used by the loop that calls t.Run and
ensure decision constants (decisionAllowOnce, decisionRejectOnce) remain
unchanged.
internal/acp/handlers_test.go-339-339 (1)

339-339: ⚠️ Potential issue | 🟡 Minor

Mutate raw with a different byte so clone validation is real.

Line 339 writes '{', which usually keeps the payload unchanged for object JSON, so this can miss aliasing bugs in emitPermissionEvent.

Suggested fix
-			raw[0] = '{'
+			raw[0] = '['
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/acp/handlers_test.go` at line 339, The test mutates the raw byte
slice using raw[0] = '{', which often leaves JSON object payloads unchanged and
can hide aliasing bugs in emitPermissionEvent; change the mutation to a
different byte that will alter the serialized payload (e.g., flip a letter or
use a byte that is not identical to the original JSON first byte) so the clone
validation is meaningful, update the test that constructs raw and calls
emitPermissionEvent to assert that the original raw remains unchanged after the
call, and reference the raw variable and emitPermissionEvent function when
making the assertion.
internal/daemon/daemon_integration_test.go-23-30 (1)

23-30: ⚠️ Potential issue | 🟡 Minor

Missing bounds check can cause test panics.

The promptCall method accesses f.promptCalls[index] without validating that index is within bounds. This could cause panics in tests if an incorrect index is passed.

🛡️ Proposed fix to add bounds validation
 func (f *fakeSessionManager) promptCall(index int) struct {
 	id  string
 	msg string
 } {
 	f.mu.Lock()
 	defer f.mu.Unlock()
+	if index < 0 || index >= len(f.promptCalls) {
+		return struct{ id, msg string }{}
+	}
 	return f.promptCalls[index]
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/daemon/daemon_integration_test.go` around lines 23 - 30, The
promptCall method reads f.promptCalls[index] without bounds checking which can
panic; update fakeSessionManager.promptCall to validate index (index >= 0 &&
index < len(f.promptCalls)) while holding f.mu and if out of range return the
zero-value struct (or a clear error/indicator) instead of indexing out of
bounds; reference the method name promptCall and the slice f.promptCalls when
making this change.
internal/api/httpapi/prompt.go-79-80 (1)

79-80: ⚠️ Potential issue | 🟡 Minor

Keep the 400 bind error message client-facing.

RespondError returns the raw error text for non-5xx statuses, so this wrapped error will expose httpapi: decode prompt request: ... in the public response body. Pass a request-level bind error here and keep the transport-specific context for logs only.

🤖 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 79 - 80, The current bind error
passed to core.RespondError wraps the transport-specific context and will be
exposed to clients; replace the wrapped error with a simple request-level error
message (e.g., "invalid JSON in request body" or "invalid request payload") when
calling core.RespondError after c.ShouldBindJSON(&req) fails, and move the
fmt.Errorf("httpapi: decode prompt request: %w", err) into a separate
server-side log call so the detailed context is retained in logs but not
returned to the client; update the call site around c.ShouldBindJSON,
core.RespondError, and the local err variable accordingly.
internal/session/manager_lifecycle.go-386-394 (1)

386-394: ⚠️ Potential issue | 🟡 Minor

Same pattern: cancel not deferred.

Same issue as above — cancel() should be deferred for safety.

🛡️ Proposed fix
 	if proc != nil {
 		stopCtx, cancel := context.WithTimeout(context.Background(), defaultLifecycleTimeout)
+		defer cancel()
 		if err := m.driver.Stop(stopCtx, proc); err != nil {
 			errs = append(errs, err)
 		}
-		cancel()
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/manager_lifecycle.go` around lines 386 - 394, The
cleanupFailedStart function creates a cancellable context (stopCtx, cancel) but
calls cancel() directly instead of deferring it; change the code in
cleanupFailedStart to call defer cancel() immediately after creating the context
so the cancel function is always executed (even on early returns or panics) and
keep the call sites that use m.driver.Stop(stopCtx, proc) unchanged.
internal/session/manager_lifecycle.go-362-369 (1)

362-369: ⚠️ Potential issue | 🟡 Minor

Context created but cancel not deferred.

The cancel() is called after recorder.Close, but if Close panics, the context won't be cancelled. Consider using defer cancel() immediately after context creation.

🛡️ Proposed fix
 	if recorder := session.recorderHandle(); recorder != nil {
 		closeCtx, cancel := context.WithTimeout(context.Background(), defaultLifecycleTimeout)
+		defer cancel()
 		if err := recorder.Close(closeCtx); err != nil {
 			errs = append(errs, err)
 		}
-		cancel()
 		session.setRecorder(nil)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/manager_lifecycle.go` around lines 362 - 369, The context
created for closing the recorder uses context.WithTimeout but calls cancel()
after recorder.Close, which can leak if Close panics; change the block around
session.recorderHandle() so that after creating closeCtx, cancel :=
context.WithTimeout(...) you immediately defer cancel() to guarantee
cancellation, then call recorder.Close(closeCtx) and handle errors (append to
errs) and finally call session.setRecorder(nil) as before; ensure the defer is
placed right after the WithTimeout call in the same scope that calls
recorder.Close.
internal/api/testutil/apitest.go-340-340 (1)

340-340: ⚠️ Potential issue | 🟡 Minor

SSE multi-line data handling may lose newlines.

Per the SSE specification, multiple data: lines should be concatenated with newline characters between them. The current implementation appends bytes directly without inserting newlines between consecutive data lines.

Proposed fix to preserve newlines between data lines
 		case strings.HasPrefix(line, "data: "):
-			current.Data = append(current.Data, []byte(strings.TrimPrefix(line, "data: "))...)
+			if len(current.Data) > 0 {
+				current.Data = append(current.Data, '\n')
+			}
+			current.Data = append(current.Data, []byte(strings.TrimPrefix(line, "data: "))...)
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/testutil/apitest.go` at line 340, The SSE data assembly
currently appends each "data: " line bytes directly (the append to
current.Data), which drops required newlines between multi-line SSE data fields;
update the logic that handles lines with the "data: " prefix (the code touching
current.Data) to insert a newline into current.Data before appending when
current.Data is non-empty so consecutive data: lines are joined with '\n' as per
the SSE spec.
🧹 Nitpick comments (26)
internal/cli/helpers_test.go (1)

3-15: Import grouping inconsistency.

The testutil import at line 9 is placed within the standard library imports block. Per Go conventions, imports should be grouped: standard library first, then a blank line, then third-party/internal packages.

♻️ Suggested import grouping
 import (
 	"bytes"
 	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
-	"github.com/pedronauck/agh/internal/testutil"
 	"testing"
 	"time"

 	aghconfig "github.com/pedronauck/agh/internal/config"
 	"github.com/pedronauck/agh/internal/memory"
+	"github.com/pedronauck/agh/internal/testutil"
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/helpers_test.go` around lines 3 - 15, The import block in
helpers_test.go incorrectly places github.com/pedronauck/agh/internal/testutil
inside the standard library group; reorder imports to follow Go conventions:
first group standard libraries (bytes, context, encoding/json, errors, fmt,
testing, time), then a blank line, then internal/third-party packages
(github.com/pedronauck/agh/internal/testutil, aghconfig from
github.com/pedronauck/agh/internal/config, and
github.com/pedronauck/agh/internal/memory) so the file compiles with consistent
import grouping.
internal/procutil/procutil_test.go (1)

20-29: Use named Should... subtests for the negative Alive cases.

Repeated "pid" subtests end up as pid/pid#01, which makes failures harder to scan and misses the repo’s test naming convention.

♻️ Suggested refactor
-	testCases := []int{0, -1}
-	for _, pid := range testCases {
-		pid := pid
-		t.Run("pid", func(t *testing.T) {
+	testCases := []struct {
+		name string
+		pid  int
+	}{
+		{name: "ShouldRejectPID0", pid: 0},
+		{name: "ShouldRejectNegativePID", pid: -1},
+	}
+	for _, tc := range testCases {
+		tc := tc
+		t.Run(tc.name, func(t *testing.T) {
 			t.Parallel()
-			if Alive(pid) {
-				t.Fatalf("Alive(%d) = true, want false", pid)
+			if Alive(tc.pid) {
+				t.Fatalf("Alive(%d) = true, want false", tc.pid)
 			}
 		})
 	}

As per coding guidelines, 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/procutil/procutil_test.go` around lines 20 - 29, The subtests use a
repeated literal name "pid" which produces non-descriptive names and violates
the repo convention; update the loop over testCases in procutil_test.go to call
t.Run with a descriptive name like fmt.Sprintf("ShouldReturnFalseForPID_%d",
pid) (or "ShouldNotBeAlive_<pid>") and pass the pid into the closure (keeping
the existing pid := pid capture pattern) so each invocation of Alive(pid) runs
as a uniquely named subtest; ensure you reference the same testCases slice and
Alive function and preserve t.Parallel() inside each subtest.
internal/memory/lock_test.go (1)

348-356: Move this check back to internal/procutil or rewrite it around lock behavior.

TestProcessAlive now exercises procutil.Alive directly, so internal/memory is no longer testing its own behavior here. That duplicates the new internal/procutil coverage and adds cross-package maintenance for no extra signal.

As per coding guidelines, MUST test meaningful business logic, not trivial operations and MUST avoid redundant validation tests across packages.

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

In `@internal/memory/lock_test.go` around lines 348 - 356, The TestProcessAlive in
internal/memory is directly calling procutil.Alive and should be moved or
repurposed: either relocate this test to internal/procutil (keeping the name
TestProcessAlive and asserting procutil.Alive(os.Getpid()) true and
procutil.Alive(-1) false), or change the test in internal/memory to exercise
lock-related behavior instead (e.g., exercise the Lock/Unlock or TryLock
semantics in the memory locker implementation and assert expected
liveliness/error conditions) so it no longer duplicates procutil coverage;
update or remove TestProcessAlive in internal/memory accordingly and ensure any
referenced symbols (TestProcessAlive, procutil.Alive, the memory lock methods
like Lock/Unlock/TryLock) are adjusted to match the chosen approach.
internal/daemon/notifier.go (1)

10-13: Add the compile-time session.Notifier assertion.

This type is clearly intended to satisfy session.Notifier; pinning that with a var _ ... assertion will catch interface drift at build time instead of during wiring or tests.

♻️ Suggested fix
 type notifierFanout struct {
 	notifiers        []session.Notifier
 	onSessionStopped func(context.Context, *session.Session)
 }
+
+var _ session.Notifier = (*notifierFanout)(nil)

As per coding guidelines, Compile-time interface verification with var _ Interface = (*Type)(nil).

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

In `@internal/daemon/notifier.go` around lines 10 - 13, Add a compile-time
interface verification asserting that notifierFanout implements session.Notifier
by adding a var declaration that assigns a nil pointer of notifierFanout to a
variable of type session.Notifier (place this statement near the notifierFanout
type or at the bottom of the file so build-time interface drift is caught
early).
internal/config/agent.go (1)

227-235: Keep the mapped frontmatter error in the chain.

Returning fresh errors.New(...) values here discards the original sentinel, so downstream code can’t use errors.Is and tests are forced into exact string matching. Prefer config-level sentinel errors wrapped with %w over replacing the error outright.

As per coding guidelines, Use errors.Is() and errors.As() for error matching — never compare error strings and 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/config/agent.go` around lines 227 - 235, Wrap and preserve the
original frontmatter sentinel errors in wrapFrontmatterError so callers can use
errors.Is/As: instead of returning fresh errors.New("config: ..."), return
config-level sentinel errors that wrap the original error using %w (e.g., map
frontmatter.ErrMissing and frontmatter.ErrUnterminated to distinct config
package sentinel errors and wrap the original err). Update wrapFrontmatterError
to return those wrapped sentinel errors (referencing wrapFrontmatterError,
frontmatter.ErrMissing, frontmatter.ErrUnterminated and the new config sentinel
names) so downstream code and tests can match using errors.Is.
internal/memory/consolidation/runtime.go (1)

391-394: Detach cleanup without dropping context values.

The fresh stop context makes sense, but building it from context.Background() loses request-scoped values and hardcodes the 10s policy in code. Prefer deriving a non-canceling context from ctx and inject the timeout from config/options.

As per coding guidelines, Use context.Context as first argument to functions crossing runtime boundaries — avoid context.Background() outside main and focused tests and 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/memory/consolidation/runtime.go` around lines 391 - 394, Replace the
ad-hoc background context and hardcoded 10s with a timeout derived from the
incoming request context and a configurable timeout option: call
context.WithTimeout(ctx, opts.SessionStopTimeout) (or similar config value)
instead of context.WithTimeout(context.Background(), 10*time.Second), keep the
defer cancel(), and pass the resulting stopCtx to sessions.Stop(dreamSession.ID)
so request-scoped values are preserved and the timeout is configurable; update
any surrounding code to accept or access the options value used for
SessionStopTimeout.
internal/session/query_test.go (1)

4-14: Import ordering: group standard library imports first.

The testutil import is placed before standard library imports (os, path/filepath, strings, testing, time). Consider grouping imports conventionally.

♻️ Suggested import ordering
 import (
 	"context"
 	"errors"
-	"github.com/pedronauck/agh/internal/testutil"
 	"os"
 	"path/filepath"
 	"strings"
 	"testing"
 	"time"
 
 	"github.com/pedronauck/agh/internal/store"
+	"github.com/pedronauck/agh/internal/testutil"
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/query_test.go` around lines 4 - 14, Reorder the import block
so standard library packages (context, errors, os, path/filepath, strings,
testing, time) are grouped first, followed by internal and third-party imports
like github.com/pedronauck/agh/internal/testutil and
github.com/pedronauck/agh/internal/store; update the import declaration at the
top of the query_test.go file (the import block that currently places testutil
before os/path/filepath) to follow Go's conventional grouping and ordering.
internal/observe/observer_integration_test.go (1)

5-13: Import ordering: group standard library imports before local packages.

The testutil import is placed before testing and time. Go convention groups imports as: standard library, then external packages, then local packages.

♻️ Suggested import ordering
 import (
-	"github.com/pedronauck/agh/internal/testutil"
 	"testing"
 	"time"
 
 	"github.com/pedronauck/agh/internal/acp"
 	"github.com/pedronauck/agh/internal/session"
 	"github.com/pedronauck/agh/internal/store"
+	"github.com/pedronauck/agh/internal/testutil"
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/observe/observer_integration_test.go` around lines 5 - 13, Reorder
the import block so standard library packages come first: place "testing" and
"time" before all other imports, then external packages, and finally local
packages like "github.com/pedronauck/agh/internal/testutil",
"github.com/pedronauck/agh/internal/acp",
"github.com/pedronauck/agh/internal/session", and
"github.com/pedronauck/agh/internal/store" to follow Go import grouping
conventions.
internal/api/testutil/apitest_test.go (1)

10-12: Consider removing this redundant test file.

Per coding guidelines, compile-time interface verification should use var _ Interface = (*Type)(nil) in production code, not in tests. The AI summary indicates that apitest.go already contains compile-time interface compliance assertions for StubSessionManager, StubObserver, and StubWorkspaceService. This test file duplicates that verification without adding value.

If the assertion in apitest.go is present, this test can be deleted. If not, move the assertion there:

// In apitest.go
var _ core.SessionManager = StubSessionManager{}

As per coding guidelines: "Use compile-time interface verification: var _ Interface = (*Type)(nil)"

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

In `@internal/api/testutil/apitest_test.go` around lines 10 - 12, The test
TestStubSessionManagerSatisfiesInterface is redundant; remove this test file or
the test function and instead ensure a compile-time interface assertion exists
in apitest.go using the StubSessionManager type against core.SessionManager
(e.g., add a package-level assertion there referencing StubSessionManager and
core.SessionManager); if apitest.go already contains the assertion, simply
delete TestStubSessionManagerSatisfiesInterface to avoid duplication.
internal/cli/render_test.go (1)

199-206: Add t.Helper() to the test helper function.

Test helper functions should call t.Helper() so that test failure line numbers point to the calling test rather than within the helper.

♻️ Proposed fix
-func newOutputTestCommand(mode OutputFormat) (*cobra.Command, *bytes.Buffer) {
+func newOutputTestCommand(t *testing.T, mode OutputFormat) (*cobra.Command, *bytes.Buffer) {
+	t.Helper()
 	cmd := &cobra.Command{Use: "test"}
 	output := &bytes.Buffer{}
 	cmd.SetOut(output)
 	cmd.Flags().String(outputFlagName, string(OutputHuman), "output format")
 	_ = cmd.Flags().Set(outputFlagName, string(mode))
 	return cmd, output
 }

Note: Update the call site at line 149 to pass t as well.

As per coding guidelines: "Use t.Helper() on test helper functions in Go tests"

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

In `@internal/cli/render_test.go` around lines 199 - 206, The test helper
newOutputTestCommand lacks a t.Helper() call, so add t.Helper() at the start of
newOutputTestCommand and change its signature to accept testing.TB (or
*testing.T) to allow calling t.Helper(); update the caller at the previous call
site to pass t into newOutputTestCommand and adjust references to outputFlagName
and OutputFormat parameters accordingly so tests report failures at the caller
frame.
internal/api/core/conversions_parsers_test.go (2)

78-79: Variable shadows context package import.

The variable context on line 79 shadows the context package imported on line 4. While this doesn't cause a bug here since the test doesn't use the context package directly after this point, it's a code smell that can cause confusion.

♻️ Rename variable to avoid shadowing
 	recorder := httptest.NewRecorder()
-	context, _ := gin.CreateTestContext(recorder)
-	context.Request = httptest.NewRequest(http.MethodGet, "/events?type=agent_message&agent_name=coder&turn_id=turn-1&after_sequence=5&limit=10&since=2026-04-03T12:00:00Z", nil)
+	ginCtx, _ := gin.CreateTestContext(recorder)
+	ginCtx.Request = httptest.NewRequest(http.MethodGet, "/events?type=agent_message&agent_name=coder&turn_id=turn-1&after_sequence=5&limit=10&since=2026-04-03T12:00:00Z", nil)
 
-	query, err := core.ParseSessionEventQuery(context)
+	query, err := core.ParseSessionEventQuery(ginCtx)

Apply the same rename pattern throughout the file for consistency.

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

In `@internal/api/core/conversions_parsers_test.go` around lines 78 - 79, The test
code declares a local variable named `context` which shadows the imported
`context` package; rename the local variable returned by `gin.CreateTestContext`
(for example to `ctx` or `ginCtx`) in the `conversions_parsers_test.go` test and
update all uses in that file (e.g., references that currently use `context`) to
the new name so the package import is no longer shadowed.

135-149: Consider using t.Parallel() for subtests.

The table-driven test subtests are independent and could benefit from parallel execution per coding guidelines.

♻️ Add t.Parallel() to subtests
 		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
 			recorder := httptest.NewRecorder()
 			context, _ := gin.CreateTestContext(recorder)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/core/conversions_parsers_test.go` around lines 135 - 149, The
subtests inside the table-driven test use t.Run and are independent, so add
t.Parallel() as the first statement inside the subtest closure (the anonymous
func passed to t.Run) to enable parallel execution; ensure any shared state is
not accessed concurrently (the current recorder and context creation inside the
closure is fine). Locate the t.Run(...) anonymous function around
core.RespondError usage and insert t.Parallel() at the top of that closure.
internal/session/manager_test.go (1)

483-497: Consider using t.Parallel() in table-driven subtests.

Per coding guidelines, independent subtests should use t.Parallel(). The subtests here are independent and could benefit from parallel execution.

♻️ Optional: Add t.Parallel() to subtests
 	for _, tc := range testCases {
-		tc := tc
 		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
 			h.driver.approveHook = func(*fakeProcess, acp.ApproveRequest) error {
 				return tc.hookErr
 			}

Note: This may require adjusting the test setup since h.driver.approveHook is shared state.

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

In `@internal/session/manager_test.go` around lines 483 - 497, The subtests in the
table-driven loop should run in parallel: inside the t.Run closure call
t.Parallel() as the first statement to enable parallel execution of each tc;
because h.driver.approveHook is shared state, ensure each subtest gets its own
isolated state before calling h.manager.ApprovePermission — e.g., clone or
recreate the handler/driver per test case or set a per-subtest local driver
(avoid mutating the shared h.driver), and assign the approveHook on that local
instance so concurrent subtests do not race on h.driver.approveHook while still
testing the same behavior.
internal/api/core/memory_workspace_test.go (1)

4-6: Avoid ignoring json.Marshal in the helper.

Even in tests, the repo's Go rules require every error to be handled. Here you're only using JSON encoding to quote a string, so strconv.Quote keeps the helper simple without dropping an error.

♻️ Suggested change
-import (
-	"encoding/json"
+import (
 	"errors"
 	"net/http"
 	"path/filepath"
+	"strconv"
 	"testing"
 	"time"
@@
 func escapeJSON(value string) string {
-	payload, _ := json.Marshal(value)
-	return string(payload[1 : len(payload)-1])
+	quoted := strconv.Quote(value)
+	return quoted[1 : len(quoted)-1]
 }

As per coding guidelines, Never ignore errors with _ — every error must be handled or have a written justification.

Also applies to: 254-256

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

In `@internal/api/core/memory_workspace_test.go` around lines 4 - 6, The test
helper currently uses json.Marshal to quote a string and ignores its error;
replace that usage with strconv.Quote (or, if you must keep json.Marshal,
capture and handle its error) so no error is discarded. Locate the helper in
memory_workspace_test.go that calls json.Marshal and swap it to strconv.Quote
for simplicity (or add proper error handling around json.Marshal) and update
imports (remove "encoding/json", add "strconv" if needed).
internal/api/core/parsers.go (1)

13-13: Minor: Unnecessary constant redefinition.

timeRFC3339Nano is just time.RFC3339Nano. Consider using the standard library constant directly.

-const timeRFC3339Nano = time.RFC3339Nano

Then update usages to time.RFC3339Nano.

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

In `@internal/api/core/parsers.go` at line 13, Remove the redundant constant
timeRFC3339Nano and replace all its usages with the standard library constant
time.RFC3339Nano; specifically delete the const declaration in
internal/api/core/parsers.go (timeRFC3339Nano) and update any references in
functions or methods that currently use timeRFC3339Nano to use time.RFC3339Nano
instead.
internal/api/httpapi/server.go (1)

19-20: Minor: Redundant import alias.

The alias core on line 20 matches the package name, making it redundant. Consider removing it for consistency.

 	"github.com/pedronauck/agh/internal/api/contract"
-	core "github.com/pedronauck/agh/internal/api/core"
+	"github.com/pedronauck/agh/internal/api/core"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/httpapi/server.go` around lines 19 - 20, Remove the redundant
import alias `core` in the import block (the import currently written as `core
"github.com/pedronauck/agh/internal/api/core"`); change it to a plain import of
the package and ensure any references to core.* remain valid (no code changes
should be necessary because the alias matches the package name).
internal/api/core/error_paths_test.go (2)

69-95: Consider using t.Run for table-driven subtests.

The loop over requests would benefit from t.Run for better test isolation and clearer failure messages. This aligns with the coding guidelines for table-driven tests.

 	for _, request := range requests {
+		t.Run(request.method+" "+request.path, func(t *testing.T) {
+			t.Parallel()
 		resp := performRequest(t, fixture.Engine, request.method, request.path, request.body)
 		if resp.Code != request.want {
 			t.Fatalf("%s %s status = %d, want %d; body=%s", request.method, request.path, resp.Code, request.want, resp.Body.String())
 		}
+		})
 	}

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

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

In `@internal/api/core/error_paths_test.go` around lines 69 - 95, The test
iterates over the requests table without subtests; wrap each table entry in
t.Run (use a descriptive name like request.method+" "+request.path) and run the
body of the loop inside the subtest closure (capture request into a local
variable to avoid loop variable capture) where you call performRequest(t,
fixture.Engine, request.method, request.path, request.body) and assert resp.Code
== request.want; this will provide isolated failures and clearer messages for
the requests slice checks in the test (reference performRequest and the requests
variable).

226-241: Consider using t.Run for table-driven subtests.

Similar to the earlier suggestion, this loop would benefit from t.Run for better test isolation.

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

In `@internal/api/core/error_paths_test.go` around lines 226 - 241, The
table-driven loop over requests should use t.Run for isolation: inside the loop
over the requests slice (the variable named requests) wrap each iteration in
t.Run(fmt.Sprintf("%s %s", req.method, req.path), func(t *testing.T) { req :=
request // capture loop variable; resp := performRequest(t,
noStoreFixture.Engine, req.method, req.path, req.body); if resp.Code !=
http.StatusInternalServerError { t.Fatalf(...) } }), and optionally call
t.Parallel() inside the subtest if parallel execution is desired; this ensures
each performRequest invocation is isolated and avoids loop-variable capture
issues.
internal/api/core/more_coverage_test.go (1)

154-158: Questionable assertion logic for TransportName default.

The condition handlers.TransportName != "" && handlers.TransportName != "apicore" will only fail if TransportName is a non-empty string other than "apicore". This means empty string passes the test, which seems to be the expected default. Consider clarifying the assertion:

 	handlers := core.NewBaseHandlers(core.BaseHandlerConfig{})
-	if handlers.TransportName != "" && handlers.TransportName != "apicore" {
-		t.Fatalf("TransportName default = %q", handlers.TransportName)
+	if handlers.TransportName != "" {
+		t.Fatalf("TransportName default = %q, want empty", handlers.TransportName)
 	}
🤖 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 154 - 158, The current
assertion uses a compound condition that lets an empty TransportName slip
through; change the test in more_coverage_test.go to explicitly assert the
expected default for TransportName returned by
core.NewBaseHandlers(core.BaseHandlerConfig{}). Locate the creation of handlers
(handlers := core.NewBaseHandlers(core.BaseHandlerConfig{})) and replace the
ambiguous check with a clear assertion such as verifying handlers.TransportName
== "" (or the exact expected string like "apicore" if that is intended) and call
t.Fatalf with the actual value when it doesn't match.
internal/session/manager_prompt.go (1)

14-62: Consider documenting or tracking the goroutine lifecycle.

The goroutine at line 60 (go m.pumpPrompt(...)) is not tracked with a sync.WaitGroup or equivalent. While the channel-based design ensures the goroutine terminates when the source closes, callers have no way to wait for pump completion.

This may be intentional for the streaming use case, but per coding guidelines: "No fire-and-forget goroutines — track with sync.WaitGroup or equivalent."

If tracking is not needed, consider adding a brief comment explaining why (e.g., "// goroutine terminates when source channel closes").

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

In `@internal/session/manager_prompt.go` around lines 14 - 62, The goroutine
started in Manager.Prompt (go m.pumpPrompt(...)) is currently fire-and-forget;
either track it with a sync.WaitGroup or document why it's safe. To fix, add a
sync.WaitGroup field (e.g., wg sync.WaitGroup) to Manager, call m.wg.Add(1)
immediately before spawning the goroutine in Prompt, and update pumpPrompt to
call defer m.wg.Done() at the start so callers can wait on m.wg.Wait() when
needed; alternatively, if you intentionally do not track it, add a concise
comment above the go m.pumpPrompt(...) line explaining that the goroutine always
terminates when the source channel closes and therefore is safe to spawn without
a WaitGroup.
internal/api/core/workspaces.go (1)

184-198: Consider removing trivial wrapper functions.

These one-liner functions add an unnecessary layer of indirection without providing additional functionality. They simply delegate to *Internal counterparts with identical signatures.

If the intent is to allow future extension or testing seams, consider documenting that purpose. Otherwise, calling the internal functions directly would reduce code surface area.

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

In `@internal/api/core/workspaces.go` around lines 184 - 198, Remove the trivial
one-line wrapper functions filterSessionInfosByWorkspaceID,
validateAbsolutePath, validateAbsolutePaths, and trimStringSlice and update all
call sites to call their corresponding internal implementations
(filterSessionInfosByWorkspaceIDInternal, validateAbsolutePathInternal,
validateAbsolutePathsInternal, trimStringSliceInternal) directly; if these
wrappers were intended as a documented extension or test seam, instead add a
short comment above each wrapper explaining that intent—otherwise delete the
wrappers, run tests, and fix any import/visibility issues that arise from the
change.
internal/api/core/handlers_test.go (2)

262-277: Test verifies stub behavior rather than handler logic.

This test calls manager.ApprovePermission directly on the stub without invoking any HTTP handler. While it validates the stub wiring, it doesn't exercise the actual HTTP endpoint or handler path.

Consider either removing this test (if stub behavior is obvious) or converting it to test the actual /sessions/{id}/approve endpoint if one exists.

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

In `@internal/api/core/handlers_test.go` around lines 262 - 277, The test
TestBaseHandlersApprovePermissionGapResolvedInStub is exercising the stub
directly (calling manager.ApprovePermission) instead of the HTTP handler; update
it to exercise the actual handler for the /sessions/{id}/approve endpoint or
remove it. Specifically, replace the direct stub call in
TestBaseHandlersApprovePermissionGapResolvedInStub with an HTTP request against
the handler that routes to the session manager (or construct the handler and
call ServeHTTP) so the test invokes the handler path that uses the session
manager's Approve method, asserting the same id and acp.ApproveRequest.TurnID
behavior; alternatively, if the stub wiring is trivial, delete this test to
avoid redundant coverage.

20-147: Consider using t.Run subtests for better test isolation and reporting.

This test function validates multiple endpoints but uses sequential assertions without t.Run. Per coding guidelines, tests should use t.Run("Should...") pattern for each test case. This would provide:

  • Better failure isolation (one failing case doesn't skip others)
  • Clearer test output showing which specific endpoint failed
  • Ability to run individual subtests

Example structure:

t.Run("Should list sessions", func(t *testing.T) {
    listResp := performRequest(t, fixture.Engine, http.MethodGet, "/sessions", nil)
    if listResp.Code != http.StatusOK {
        t.Fatalf("list status = %d, want %d", listResp.Code, http.StatusOK)
    }
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/core/handlers_test.go` around lines 20 - 147, The test
TestBaseHandlersSessionEndpoints runs many endpoint checks sequentially;
refactor it to use t.Run subtests so each endpoint assertion is isolated and
reported separately: wrap each performRequest + assertion block in t.Run with
descriptive names (e.g., "Should list sessions", "Should create session",
"Should get session", "Should return 404 for missing session", "Should stop
session", "Should resume session", "Should get events", "Should get history",
"Should get transcript"), keeping the same fixture, manager (including
createCalled atomic), and assertions, and ensure any per-subtest state (if
needed) is local to that t.Run closure; keep function name
TestBaseHandlersSessionEndpoints and the existing performRequest calls and
response checks unchanged except for moving them into the t.Run closures.
internal/api/core/handlers.go (1)

561-593: DaemonStatus uses os.Getpid() directly instead of injected dependency.

The DaemonStatus handler calls os.Getpid() directly (Line 583), while the daemon struct has an injected pid function for testability. For consistency and testability, consider using an injected PID source.

This is a minor inconsistency since status endpoints are typically not unit-tested in isolation.

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

In `@internal/api/core/handlers.go` around lines 561 - 593, DaemonStatus calls
os.Getpid() directly; replace that call with the injected PID provider on the
handler (e.g., use h.Pid() or the handler's pid function) so the PID is sourced
from the injected dependency for testability and consistency with BaseHandlers;
update the struct reference in DaemonStatus (where PID is set) to call the
injected function instead of os.Getpid().
internal/api/core/interfaces.go (1)

21-33: Consider documenting the distinction between List() and ListAll().

List() takes no context while ListAll() does. This asymmetry suggests List() returns cached in-memory sessions while ListAll() may perform I/O. A brief doc comment clarifying when to use each would help implementers and consumers.

Suggested documentation
 // SessionManager is the runtime session surface exposed by API transports.
 type SessionManager interface {
 	Create(ctx context.Context, opts session.CreateOpts) (*session.Session, error)
+	// List returns currently active in-memory sessions without I/O.
 	List() []*session.SessionInfo
+	// ListAll retrieves all sessions including persisted ones; may perform I/O.
 	ListAll(ctx context.Context) ([]*session.SessionInfo, error)
 	Status(ctx context.Context, id string) (*session.SessionInfo, error)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/core/interfaces.go` around lines 21 - 33, Add a brief doc
comment on the SessionManager interface clarifying the behavioral difference
between List() and ListAll(): state that List() is a fast/cached, in-memory
snapshot that takes no context and should be used for inexpensive, non-blocking
reads of currently tracked sessions, whereas ListAll(ctx context.Context) may
perform I/O or long-running operations (and thus accepts a context) to return a
full authoritative list; attach this comment immediately above the
SessionManager type and mention the two methods by name (List and ListAll) so
implementers and callers understand which to use.
internal/api/testutil/apitest.go (1)

52-61: Silently ignoring error from ListAllFn fallback.

The List() method falls back to calling ListAllFn but discards any error it returns. While this is test utility code, silently dropping errors can mask issues in tests that rely on this fallback behavior.

Consider logging or handling the error

If the fallback is intentional, consider whether tests using List() would benefit from knowing if ListAllFn failed. Alternatively, document this behavior explicitly:

 func (s StubSessionManager) List() []*session.SessionInfo {
 	if s.ListFn != nil {
 		return s.ListFn()
 	}
 	if s.ListAllFn != nil {
-		infos, _ := s.ListAllFn(context.Background())
+		// Fallback: errors are intentionally ignored since List() has no error return.
+		infos, _ := s.ListAllFn(context.Background())
 		return infos
 	}
 	return nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/testutil/apitest.go` around lines 52 - 61, The List method on
StubSessionManager currently ignores the error returned by ListAllFn; update
StubSessionManager.List to check the (infos, err) result from ListAllFn and
handle the error instead of discarding it — e.g., if err != nil produce a
visible failure (log or panic) with a descriptive message so tests won't
silently hide failures, otherwise return infos; reference the
StubSessionManager.List method and the ListFn/ListAllFn fields when making the
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5996c634-6a84-4c31-b7cb-a9d1a00f3019

📥 Commits

Reviewing files that changed from the base of the PR and between 9c52b92 and cb41bd9.

📒 Files selected for processing (182)
  • internal/acp/client_integration_test.go
  • internal/acp/client_test.go
  • internal/acp/handlers.go
  • internal/acp/handlers_test.go
  • internal/acp/rawjson.go
  • internal/api/contract/contract.go
  • internal/api/contract/contract_test.go
  • internal/api/core/conversions.go
  • internal/api/core/conversions_parsers_test.go
  • internal/api/core/error_paths_test.go
  • internal/api/core/errors.go
  • internal/api/core/handlers.go
  • internal/api/core/handlers_test.go
  • internal/api/core/interfaces.go
  • internal/api/core/memory.go
  • internal/api/core/memory_workspace_test.go
  • internal/api/core/more_coverage_test.go
  • internal/api/core/parsers.go
  • internal/api/core/payloads.go
  • internal/api/core/session_workspace.go
  • internal/api/core/session_workspace_internal_test.go
  • internal/api/core/sse.go
  • internal/api/core/test_helpers_test.go
  • internal/api/core/workspaces.go
  • internal/api/httpapi/agents.go
  • internal/api/httpapi/daemon.go
  • internal/api/httpapi/handlers_error_test.go
  • internal/api/httpapi/handlers_test.go
  • internal/api/httpapi/helpers_integration_test.go
  • internal/api/httpapi/helpers_test.go
  • internal/api/httpapi/httpapi_integration_test.go
  • internal/api/httpapi/memory.go
  • internal/api/httpapi/memory_test.go
  • internal/api/httpapi/observe.go
  • internal/api/httpapi/prompt.go
  • internal/api/httpapi/prompt_contract_test.go
  • internal/api/httpapi/server.go
  • internal/api/httpapi/server_test.go
  • internal/api/httpapi/sessions.go
  • internal/api/httpapi/shared_test.go
  • internal/api/httpapi/static.go
  • internal/api/httpapi/static_test.go
  • internal/api/httpapi/stream.go
  • internal/api/httpapi/stream_helpers_test.go
  • internal/api/httpapi/workspaces.go
  • internal/api/testutil/apitest.go
  • internal/api/testutil/apitest_test.go
  • internal/api/udsapi/agents.go
  • internal/api/udsapi/daemon.go
  • internal/api/udsapi/handlers_error_test.go
  • internal/api/udsapi/handlers_test.go
  • internal/api/udsapi/helpers_test.go
  • internal/api/udsapi/memory.go
  • internal/api/udsapi/memory_test.go
  • internal/api/udsapi/observe.go
  • internal/api/udsapi/payloads.go
  • internal/api/udsapi/prompt.go
  • internal/api/udsapi/routes.go
  • internal/api/udsapi/server.go
  • internal/api/udsapi/server_test.go
  • internal/api/udsapi/sessions.go
  • internal/api/udsapi/shared_test.go
  • internal/api/udsapi/stream.go
  • internal/api/udsapi/stream_helpers_test.go
  • internal/api/udsapi/udsapi_integration_test.go
  • internal/api/udsapi/workspaces.go
  • internal/cli/agent.go
  • internal/cli/agent_commands_test.go
  • internal/cli/cli_integration_test.go
  • internal/cli/client.go
  • internal/cli/client_test.go
  • internal/cli/command_paths_test.go
  • internal/cli/daemon.go
  • internal/cli/daemon_wait_test.go
  • internal/cli/format.go
  • internal/cli/helpers_test.go
  • internal/cli/memory.go
  • internal/cli/memory_test.go
  • internal/cli/observe.go
  • internal/cli/render_test.go
  • internal/cli/root.go
  • internal/cli/session.go
  • internal/cli/session_test.go
  • internal/cli/skill.go
  • internal/cli/skill_test.go
  • internal/cli/workspace.go
  • internal/config/agent.go
  • internal/config/agent_test.go
  • internal/config/home.go
  • internal/config/home_test.go
  • internal/daemon/boot.go
  • internal/daemon/boundary.go
  • internal/daemon/daemon.go
  • internal/daemon/daemon_integration_test.go
  • internal/daemon/daemon_test.go
  • internal/daemon/lock.go
  • internal/daemon/notifier.go
  • internal/daemon/orphan.go
  • internal/filesnap/filesnap.go
  • internal/filesnap/filesnap_test.go
  • internal/fileutil/atomic.go
  • internal/fileutil/atomic_test.go
  • internal/frontmatter/frontmatter.go
  • internal/frontmatter/frontmatter_test.go
  • internal/httpapi/agents.go
  • internal/httpapi/daemon.go
  • internal/httpapi/helpers_test.go
  • internal/httpapi/observe.go
  • internal/httpapi/sessions.go
  • internal/httpapi/stream.go
  • internal/httpapi/workspaces.go
  • internal/memory/consolidation/runtime.go
  • internal/memory/consolidation/runtime_test.go
  • internal/memory/dream_test.go
  • internal/memory/lock.go
  • internal/memory/lock_test.go
  • internal/memory/store.go
  • internal/observe/health.go
  • internal/observe/helpers_test.go
  • internal/observe/observer.go
  • internal/observe/observer_integration_test.go
  • internal/observe/observer_test.go
  • internal/observe/reconcile_test.go
  • internal/procutil/procutil.go
  • internal/procutil/procutil_test.go
  • internal/session/additional_test.go
  • internal/session/interfaces.go
  • internal/session/manager.go
  • internal/session/manager_helpers.go
  • internal/session/manager_integration_test.go
  • internal/session/manager_lifecycle.go
  • internal/session/manager_prompt.go
  • internal/session/manager_stop_integration_test.go
  • internal/session/manager_test.go
  • internal/session/manager_workspace.go
  • internal/session/query_test.go
  • internal/session/transcript.go
  • internal/session/transcript_test.go
  • internal/skills/loader.go
  • internal/skills/loader_test.go
  • internal/skills/registry.go
  • internal/skills/registry_test.go
  • internal/skills/types.go
  • internal/skills/watcher.go
  • internal/store/global_db.go
  • internal/store/globaldb/global_db.go
  • internal/store/globaldb/global_db_extra_test.go
  • internal/store/globaldb/global_db_observe.go
  • internal/store/globaldb/global_db_permission.go
  • internal/store/globaldb/global_db_session.go
  • internal/store/globaldb/global_db_test.go
  • internal/store/globaldb/global_db_workspace.go
  • internal/store/globaldb/migrate_workspace.go
  • internal/store/meta.go
  • internal/store/schema.go
  • internal/store/sessiondb/session_db.go
  • internal/store/sessiondb/session_db_extra_test.go
  • internal/store/sessiondb/session_db_integration_test.go
  • internal/store/sessiondb/session_db_test.go
  • internal/store/sql_helpers.go
  • internal/store/sqlite.go
  • internal/store/store.go
  • internal/store/store_extra_test.go
  • internal/store/store_helpers_test.go
  • internal/store/types.go
  • internal/store/validation.go
  • internal/testutil/testutil.go
  • internal/testutil/testutil_test.go
  • internal/transcript/transcript.go
  • internal/transcript/transcript_test.go
  • internal/udsapi/handlers.go
  • internal/udsapi/helpers_test.go
  • internal/udsapi/memory.go
  • internal/udsapi/routes.go
  • internal/udsapi/workspaces.go
  • internal/workspace/clone.go
  • internal/workspace/helpers.go
  • internal/workspace/resolver.go
  • internal/workspace/resolver_crud.go
  • internal/workspace/resolver_integration_test.go
  • internal/workspace/resolver_test.go
  • internal/workspace/scanner.go
💤 Files with no reviewable changes (7)
  • internal/httpapi/daemon.go
  • internal/httpapi/sessions.go
  • internal/httpapi/stream.go
  • internal/httpapi/workspaces.go
  • internal/httpapi/observe.go
  • internal/httpapi/helpers_test.go
  • internal/httpapi/agents.go

Comment thread internal/api/core/memory_workspace_test.go
Comment thread internal/api/core/sse.go
Comment thread internal/api/httpapi/prompt_contract_test.go
Comment thread internal/daemon/boundary.go Outdated
Comment thread internal/filesnap/filesnap_test.go Outdated
Comment thread internal/procutil/procutil.go
Comment thread internal/session/manager_helpers.go Outdated
Comment thread internal/session/manager_integration_test.go Outdated
Comment thread internal/session/manager_lifecycle.go Outdated
Comment thread internal/session/manager_stop_integration_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: 7

♻️ Duplicate comments (2)
internal/api/core/sse.go (1)

97-115: ⚠️ Potential issue | 🔴 Critical

event.ID is still not a stable same-timestamp cursor key.

Line 109 and Line 115 both assume lexicographic event.ID order matches actual emission order. When two summaries share a timestamp, reconnects can replay or drop the wrong item unless the cursor uses a monotonic DB sequence or insertion-order key instead.

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

In `@internal/api/core/sse.go` around lines 97 - 115, The comparison and
Last-Event-ID construction in ObserveEventAfterCursor and ObserveEventID assume
event.ID orders lexicographically, which is unstable for same-timestamp events;
change the cursor and ID generation to use a monotonic insertion-order/sequence
value (e.g., event.Sequence or event.Serial) instead of relying on event.ID
string ordering: update ObserveEventAfterCursor to, after timestamp equality,
compare the monotonic sequence (fallback to event.ID only if sequence is
absent), and update ObserveEventID to include the timestamp + a fixed-width
zero-padded sequence (or the monotonic key) after the separator so the
Last-Event-ID is stable and preserves emission order for identical timestamps.
Ensure the cursor type ObserveCursor is updated to hold the sequence and that
any consumers use that sequence in comparisons and parsing.
internal/session/manager_lifecycle.go (1)

274-286: ⚠️ Potential issue | 🟠 Major

Pass context.Context to watchProcess and use select with ctx.Done() for cancellation.

This is the same issue flagged in a previous review. The goroutine spawned here violates coding guidelines:

  1. Missing context propagation: watchProcess(session) is called from activateAndWatch(ctx, ...) but ctx is not passed.
  2. No goroutine tracking: The goroutine cannot be cancelled and is fire-and-forget.

Per context snippet from internal/session/interfaces.go, AgentProcess has a Done() <-chan struct{} method that can be used with select.

As per coding guidelines: "Every goroutine must have explicit ownership and shutdown via context.Context cancellation" and "Use select with ctx.Done() in all long-running goroutine loops".

,

Proposed fix
-func (m *Manager) watchProcess(session *Session) {
+func (m *Manager) watchProcess(ctx context.Context, session *Session) {
 	proc := session.processHandle()
 	if proc == nil {
 		return
 	}
 
 	go func() {
-		waitErr := proc.Wait()
+		select {
+		case <-ctx.Done():
+			return
+		case <-proc.Done():
+		}
+		waitErr := proc.Wait()
 		if err := m.handleProcessExit(session, waitErr); err != nil {
 			m.sessionLogger(session).Warn("session: process exit handling failed", "error", err)
 		}
 	}()
 }

And update the call in activateAndWatch (in manager_helpers.go):

-	m.watchProcess(session)
+	m.watchProcess(ctx, session)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/manager_lifecycle.go` around lines 274 - 286, The goroutine
in Manager.watchProcess is created without context propagation or cancellation;
change the signature to accept ctx (e.g., func (m *Manager) watchProcess(ctx
context.Context, session *Session)) and update the caller in activateAndWatch to
pass its ctx. Inside watchProcess, run the wait logic in a cancellable select
that listens on ctx.Done() and the process completion (use
session.processHandle().Wait() result or the process Done() channel from
AgentProcess.Done()), then call m.handleProcessExit(session, waitErr) only when
the process actually exits; ensure the goroutine returns promptly on ctx
cancellation so it is properly owned and shutdownable.
🧹 Nitpick comments (5)
internal/fileutil/atomic.go (1)

28-32: Add a comment justifying the ignored error on temp file cleanup.

The ignored error _ = os.Remove(tempPath) violates the coding guideline requiring every ignored error to have a written justification. While ignoring this error is reasonable (it's best-effort cleanup and failure doesn't affect correctness), adding a brief comment will satisfy the guideline and document the intent.

💡 Suggested fix
 	defer func() {
 		if cleanup {
-			_ = os.Remove(tempPath)
+			_ = os.Remove(tempPath) // Best-effort cleanup; temp file may already be gone or dir unwritable
 		}
 	}()

As per coding guidelines: "Never ignore errors with _ — every error must be handled or have a written justification".

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

In `@internal/fileutil/atomic.go` around lines 28 - 32, The deferred cleanup
currently calls `_ = os.Remove(tempPath)` in the anonymous func (guarded by
`cleanup`) and ignores the error; add a brief comment above that line explaining
why the error is intentionally ignored (e.g., best-effort cleanup, non-fatal,
does not affect correctness or resource safety) so it satisfies the guideline;
reference the deferred anonymous function, the `cleanup` variable, and the
`os.Remove(tempPath)` call when adding the justification comment.
internal/api/testutil/apitest.go (1)

53-65: Consider returning empty slice instead of panicking in test fallback.

The List() fallback to ListAllFn panics on error (line 60), which could cause unhelpful test failures if a test accidentally triggers this path. Since this is test utility code, a more defensive approach would help debugging.

♻️ Proposed alternative: return empty slice on fallback error
 func (s StubSessionManager) List() []*session.SessionInfo {
 	if s.ListFn != nil {
 		return s.ListFn()
 	}
 	if s.ListAllFn != nil {
 		infos, err := s.ListAllFn(context.Background())
-		if err != nil {
-			panic(fmt.Errorf("testutil: StubSessionManager.List fallback failed: %w", err))
-		}
+		if err != nil {
+			return nil // Test should set ListFn if error behavior matters
+		}
 		return infos
 	}
 	return nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/api/testutil/apitest.go` around lines 53 - 65, The
StubSessionManager.List fallback currently panics when ListAllFn returns an
error; change this to be defensive: in the List method (StubSessionManager.List)
call s.ListAllFn(context.Background()), and if it returns an error, do not
panic—return an empty slice (e.g., []*session.SessionInfo{}) instead so tests
hitting the fallback get an empty result rather than crashing; keep existing
behavior of returning s.ListFn() when present and nil only if neither handler is
provided.
internal/cli/client_test.go (1)

424-461: Consider using "Should..." naming pattern for subtests.

The table-driven test structure is good, but the subtest names like "createSessionRequest" don't follow the t.Run("Should...") pattern. As per coding guidelines: "MUST use t.Run("Should...") pattern for ALL test cases".

♻️ Suggested naming pattern
 tests := []struct {
-    name    string
+    name    string // e.g., "Should_alias_CreateSessionRequest_to_contract"
     cliType any
     want    any
 }{
-    {name: "createSessionRequest", cliType: CreateSessionRequest{}, want: contract.CreateSessionRequest{}},
-    {name: "sessionRecord", cliType: SessionRecord{}, want: contract.SessionPayload{}},
+    {name: "Should alias CreateSessionRequest to contract type", cliType: CreateSessionRequest{}, want: contract.CreateSessionRequest{}},
+    {name: "Should alias SessionRecord to contract type", cliType: SessionRecord{}, want: contract.SessionPayload{}},
     // ... similar for others
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/cli/client_test.go` around lines 424 - 461, Update the subtest names
in TestCLIUsesSharedContractAliases to follow the required t.Run("Should ...")
pattern: modify the test table entries (the name fields) or the t.Run invocation
so each subtest name is prefixed with "Should", e.g. "Should create session
request" for the CreateSessionRequest case; ensure you update all entries
(createSessionRequest, sessionRecord, sessionEventRecord, etc.) or prepend
"Should " at t.Run(tt.name, ...) (e.g. t.Run(fmt.Sprintf("Should %s", tt.name),
...)) to preserve intent and keep reflect checks unchanged.
internal/api/core/handlers.go (1)

101-103: Default StreamDone channel never signals shutdown.

When cfg.StreamDone is nil, a new channel is created at line 102 that is never closed. This means streaming handlers will only terminate via request context cancellation, never via server shutdown signal. This could leave streams running longer than expected during graceful shutdown if the caller forgets to set StreamDone.

Consider documenting this behavior or logging a warning when StreamDone is not provided.

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

In `@internal/api/core/handlers.go` around lines 101 - 103, The code creates a
default cfg.StreamDone channel but never closes it, so update the initialization
to either log a warning when StreamDone is nil or (preferably) wire the new
channel to the server shutdown lifecycle: when you allocate cfg.StreamDone,
spawn a short goroutine that waits on the server shutdown context or shutdown
signal (e.g., a provided context, cfg.ShutdownCtx, or equivalent) and closes
cfg.StreamDone when shutdown begins; reference cfg.StreamDone and add a log
entry so callers know a default channel was created if no explicit shutdown hook
exists.
internal/session/manager_lifecycle.go (1)

288-299: Consider accepting context parameter instead of using context.Background().

Line 298 uses context.Background() which the coding guidelines discourage outside main and tests. However, since handleProcessExit is called from the watchProcess goroutine after a process exits (potentially long after the original context was cancelled), using context.Background() is a reasonable choice here to ensure cleanup completes.

If watchProcess is updated to accept context (per previous comment), that context could be passed to handleProcessExit, though it might already be cancelled at this point.

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

In `@internal/session/manager_lifecycle.go` around lines 288 - 299, Change
Manager.handleProcessExit to accept a context.Context parameter and use that
context when calling finalizeStopped instead of using context.Background();
update its callers (e.g., watchProcess) to pass through the available context
(even if it may be cancelled) so the function signature is
Manager.handleProcessExit(ctx context.Context, session *Session, waitErr error)
and the call site uses that ctx when invoking m.finalizeStopped(ctx, session,
waitErr); keep references to Manager.handleProcessExit, watchProcess, and
finalizeStopped when making the edits.
🤖 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/api/core/handlers.go`:
- Around line 182-187: The handler currently omits the session Type when calling
Sessions.Create (session.CreateOpts in internal/api/core/handlers.go), which
causes normalizeSessionType to default empty string to SessionTypeUser; either
(A) add a Type field to the API contract (CreateSessionRequest) and map req.Type
into session.CreateOpts.Type so callers can create Dream/System sessions,
ensuring you validate/convert the incoming string to the internal enum
(normalizeSessionType or equivalent), or (B) if the API should only create user
sessions, explicitly set opts.Type = session.SessionTypeUser before calling
h.Sessions.Create and document that CreateSessionRequest does not support other
types — update the call site in handlers.go (the sess creation block) and the
CreateSessionRequest definition accordingly.

In `@internal/api/core/memory_workspace_test.go`:
- Line 68: Test requests interpolate workspace, rootDir, and addDir directly
into URLs and JSON, which breaks on Windows due to backslashes/spaces; update
the tests (where performRequest is called) to build query strings with
url.Values or url.QueryEscape for the workspace parameter and build JSON bodies
via json.Marshal (instead of string concatenation) for payloads that include
rootDir/addDir, ensuring all request URLs and JSON bodies are properly
escaped/encoded.
- Around line 69-71: The tests currently only assert HTTP status (e.g., the
listResp.Code check) which misses payload regressions; update each handler
subtest (those using variables like listResp, getResp, createResp, deleteResp)
to decode the JSON response body into the concrete response structs (memory
list/item struct, health/workspace DTOs used by the handlers) and add assertions
on key business fields (IDs, WorkspaceID, Name/Content, timestamps or deleted
flags, and any health fields) to verify the actual payload shape and persisted
state rather than just the status code. Ensure you call
json.NewDecoder(resp.Body).Decode(&<expectedStruct>), check for decode errors,
and replace the status-only t.Fatalf checks with both status assertions and
explicit field asserts so tests fail on contract regressions.

In `@internal/api/core/sse.go`:
- Around line 81-90: The observe cursor (ObserveCursor) is advanced before
attempting to write the SSE frame, causing skipped events on write failure;
modify EmitObserveEvents so that next = ObserveCursor{Timestamp:
event.Timestamp.UTC(), ID: event.ID} is assigned only after WriteSSE(writer,
SSEMessage{ID: ObserveEventID(event), Name: event.Type, Data:
ObserveEventPayloadFromEvent(event)}) returns nil, i.e. move the next assignment
below the successful WriteSSE call and keep returning the prior cursor on error
so reconnects can retry the unsent event.

In `@internal/daemon/boundary.go`:
- Around line 47-54: The shouldVerifyBoundaries method can panic if d.getenv is
nil; update shouldVerifyBoundaries to guard: if d.verifyBoundaries return true;
otherwise resolve an envGetter function pointer (use d.getenv if non-nil else
use os.Getenv) and call it for "AGH_DEV_VERIFY_BOUNDARIES", trim/lower it and
compare to "1"/"true"/"yes"; reference the shouldVerifyBoundaries method and the
d.getenv field when making this change.

In `@internal/session/manager_helpers.go`:
- Around line 67-84: activateAndWatch currently attaches the live AgentProcess
via session.updateFromProcess early and can return before subsequent fallible
calls (session.activate, m.writeMeta, m.activate) complete, leaking the process
or leaving session state inconsistent; fix this by reordering and/or adding
rollback: perform the fallible operations (call session.activate(now),
m.writeMeta(session), and m.activate(session)) before calling
session.updateFromProcess(ctx, proc) and only invoke m.notifier.OnSessionCreated
and m.watchProcess after those succeed, and if you prefer rollback instead,
ensure on any error after updateFromProcess you stop/terminate the AgentProcess
and clear the attached state on Session (undo whatever session.updateFromProcess
sets) and revert any written metadata (or call the corresponding metadata/
deactivate helper) so no active process or active session state remains on
error.

In `@internal/session/manager_prompt.go`:
- Around line 103-118: The pumpPrompt goroutine can hang if ctx is canceled
while still ranging over source; change the loop in Manager.pumpPrompt to select
on ctx.Done() when receiving and when sending so the goroutine exits promptly on
cancellation: replace the "for event := range source" with a loop using "select
{ case <-ctx.Done(): return; case event, ok := <-source: if !ok { return } ...
}" and keep the existing send guarded by "select { case out <- normalized: case
<-ctx.Done(): return }"; use the same symbols (pumpPrompt, normalizeEvent,
recordEvent, notifier.OnAgentEvent, sessionLogger) so the function returns when
ctx is done and out is closed via the existing defer.

---

Duplicate comments:
In `@internal/api/core/sse.go`:
- Around line 97-115: The comparison and Last-Event-ID construction in
ObserveEventAfterCursor and ObserveEventID assume event.ID orders
lexicographically, which is unstable for same-timestamp events; change the
cursor and ID generation to use a monotonic insertion-order/sequence value
(e.g., event.Sequence or event.Serial) instead of relying on event.ID string
ordering: update ObserveEventAfterCursor to, after timestamp equality, compare
the monotonic sequence (fallback to event.ID only if sequence is absent), and
update ObserveEventID to include the timestamp + a fixed-width zero-padded
sequence (or the monotonic key) after the separator so the Last-Event-ID is
stable and preserves emission order for identical timestamps. Ensure the cursor
type ObserveCursor is updated to hold the sequence and that any consumers use
that sequence in comparisons and parsing.

In `@internal/session/manager_lifecycle.go`:
- Around line 274-286: The goroutine in Manager.watchProcess is created without
context propagation or cancellation; change the signature to accept ctx (e.g.,
func (m *Manager) watchProcess(ctx context.Context, session *Session)) and
update the caller in activateAndWatch to pass its ctx. Inside watchProcess, run
the wait logic in a cancellable select that listens on ctx.Done() and the
process completion (use session.processHandle().Wait() result or the process
Done() channel from AgentProcess.Done()), then call m.handleProcessExit(session,
waitErr) only when the process actually exits; ensure the goroutine returns
promptly on ctx cancellation so it is properly owned and shutdownable.

---

Nitpick comments:
In `@internal/api/core/handlers.go`:
- Around line 101-103: The code creates a default cfg.StreamDone channel but
never closes it, so update the initialization to either log a warning when
StreamDone is nil or (preferably) wire the new channel to the server shutdown
lifecycle: when you allocate cfg.StreamDone, spawn a short goroutine that waits
on the server shutdown context or shutdown signal (e.g., a provided context,
cfg.ShutdownCtx, or equivalent) and closes cfg.StreamDone when shutdown begins;
reference cfg.StreamDone and add a log entry so callers know a default channel
was created if no explicit shutdown hook exists.

In `@internal/api/testutil/apitest.go`:
- Around line 53-65: The StubSessionManager.List fallback currently panics when
ListAllFn returns an error; change this to be defensive: in the List method
(StubSessionManager.List) call s.ListAllFn(context.Background()), and if it
returns an error, do not panic—return an empty slice (e.g.,
[]*session.SessionInfo{}) instead so tests hitting the fallback get an empty
result rather than crashing; keep existing behavior of returning s.ListFn() when
present and nil only if neither handler is provided.

In `@internal/cli/client_test.go`:
- Around line 424-461: Update the subtest names in
TestCLIUsesSharedContractAliases to follow the required t.Run("Should ...")
pattern: modify the test table entries (the name fields) or the t.Run invocation
so each subtest name is prefixed with "Should", e.g. "Should create session
request" for the CreateSessionRequest case; ensure you update all entries
(createSessionRequest, sessionRecord, sessionEventRecord, etc.) or prepend
"Should " at t.Run(tt.name, ...) (e.g. t.Run(fmt.Sprintf("Should %s", tt.name),
...)) to preserve intent and keep reflect checks unchanged.

In `@internal/fileutil/atomic.go`:
- Around line 28-32: The deferred cleanup currently calls `_ =
os.Remove(tempPath)` in the anonymous func (guarded by `cleanup`) and ignores
the error; add a brief comment above that line explaining why the error is
intentionally ignored (e.g., best-effort cleanup, non-fatal, does not affect
correctness or resource safety) so it satisfies the guideline; reference the
deferred anonymous function, the `cleanup` variable, and the
`os.Remove(tempPath)` call when adding the justification comment.

In `@internal/session/manager_lifecycle.go`:
- Around line 288-299: Change Manager.handleProcessExit to accept a
context.Context parameter and use that context when calling finalizeStopped
instead of using context.Background(); update its callers (e.g., watchProcess)
to pass through the available context (even if it may be cancelled) so the
function signature is Manager.handleProcessExit(ctx context.Context, session
*Session, waitErr error) and the call site uses that ctx when invoking
m.finalizeStopped(ctx, session, waitErr); keep references to
Manager.handleProcessExit, watchProcess, and finalizeStopped when making the
edits.
🪄 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: 50797426-42aa-402b-a345-a753833424d2

📥 Commits

Reviewing files that changed from the base of the PR and between cb41bd9 and c1f1b35.

📒 Files selected for processing (49)
  • internal/acp/handlers_test.go
  • internal/api/core/conversions_parsers_test.go
  • internal/api/core/error_paths_test.go
  • internal/api/core/handlers.go
  • internal/api/core/handlers_test.go
  • internal/api/core/interfaces.go
  • internal/api/core/memory_workspace_test.go
  • internal/api/core/more_coverage_test.go
  • internal/api/core/parsers.go
  • internal/api/core/sse.go
  • internal/api/core/workspaces.go
  • internal/api/httpapi/httpapi_integration_test.go
  • internal/api/httpapi/prompt.go
  • internal/api/httpapi/prompt_contract_test.go
  • internal/api/httpapi/server.go
  • internal/api/testutil/apitest.go
  • internal/api/udsapi/udsapi_integration_test.go
  • internal/cli/client.go
  • internal/cli/client_test.go
  • internal/cli/helpers_test.go
  • internal/cli/render_test.go
  • internal/config/agent.go
  • internal/config/agent_test.go
  • internal/daemon/boundary.go
  • internal/daemon/daemon_integration_test.go
  • internal/daemon/daemon_test.go
  • internal/daemon/notifier.go
  • internal/filesnap/filesnap.go
  • internal/filesnap/filesnap_test.go
  • internal/fileutil/atomic.go
  • internal/fileutil/atomic_dirsync_unix.go
  • internal/fileutil/atomic_dirsync_windows.go
  • internal/fileutil/atomic_test.go
  • internal/frontmatter/frontmatter.go
  • internal/frontmatter/frontmatter_test.go
  • internal/memory/consolidation/runtime.go
  • internal/memory/consolidation/runtime_test.go
  • internal/memory/lock_test.go
  • internal/observe/observer_integration_test.go
  • internal/procutil/procutil.go
  • internal/procutil/procutil_test.go
  • internal/procutil/procutil_windows.go
  • internal/session/manager_helpers.go
  • internal/session/manager_integration_test.go
  • internal/session/manager_lifecycle.go
  • internal/session/manager_prompt.go
  • internal/session/manager_stop_integration_test.go
  • internal/session/manager_test.go
  • internal/session/query_test.go
💤 Files with no reviewable changes (1)
  • internal/memory/lock_test.go
✅ Files skipped from review due to trivial changes (10)
  • internal/cli/helpers_test.go
  • internal/observe/observer_integration_test.go
  • internal/filesnap/filesnap_test.go
  • internal/cli/render_test.go
  • internal/api/core/conversions_parsers_test.go
  • internal/filesnap/filesnap.go
  • internal/api/core/more_coverage_test.go
  • internal/api/core/parsers.go
  • internal/api/core/error_paths_test.go
  • internal/api/core/interfaces.go
🚧 Files skipped from review as they are similar to previous changes (13)
  • internal/acp/handlers_test.go
  • internal/config/agent.go
  • internal/procutil/procutil_test.go
  • internal/procutil/procutil.go
  • internal/config/agent_test.go
  • internal/daemon/daemon_integration_test.go
  • internal/frontmatter/frontmatter_test.go
  • internal/frontmatter/frontmatter.go
  • internal/daemon/notifier.go
  • internal/api/httpapi/prompt.go
  • internal/api/core/handlers_test.go
  • internal/memory/consolidation/runtime_test.go
  • internal/memory/consolidation/runtime.go

Comment thread internal/api/core/handlers.go
Comment thread internal/api/core/memory_workspace_test.go Outdated
Comment thread internal/api/core/memory_workspace_test.go
Comment thread internal/api/core/sse.go Outdated
Comment thread internal/daemon/boundary.go
Comment thread internal/session/manager_helpers.go
Comment thread internal/session/manager_prompt.go
@pedronauck pedronauck merged commit d3190ff into main Apr 7, 2026
1 check was pending
@pedronauck pedronauck deleted the pn/refactoring branch April 7, 2026 18:19
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