Skip to content

Latest commit

 

History

History
864 lines (598 loc) · 146 KB

File metadata and controls

864 lines (598 loc) · 146 KB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

Changed

  • OAK is in maintenance mode. This project is no longer under active development. I have since started Myco, a new project originally inspired by ideas explored in OAK. Myco goes beyond memory and unlocks true intelligence for your project and your team. Moving over? See the migration guide.

[2026-03-20]

Fixed

  • Fix MCP server install silently skipped after MCP_SERVER_NAME constant was removed in a prior refactor — pipeline stages mcp.py and removal.py were importing the constant from features/team/constants.py, which no longer existed; corrected import to features/swarm/constants.py with the updated constant name, ensuring the MCP server is correctly identified and installed during oak init and oak upgrade

  • Fix stale PID files blocking daemon restarts — the cleanup routine in utils/daemon_manager.py compared the PID filename against a hard-coded string rather than the resolved absolute path; the condition never matched when the file lived in a different directory, so the PID file was never removed on unexpected process exit; path is now normalised with os.path.abspath before comparison

  • Fix ModuleNotFoundError on daemon startup caused by typo open_agent_kit.confi — corrected to open_agent_kit.config.path and reordered the import block to satisfy lint; see team/daemon/lifecycle/startup.py

  • Fix TypeScript TS2304 errors in relay-object.tsCAPABILITY_SWARM_TOOLS and CAPABILITY_SWARM_BROADCAST were declared after the code that referenced them; const is block-scoped and not hoisted, so the compiler reported them as undefined; moved declarations to the top of the file

  • Fix missing @cloudflare/workers-types package causing worker build failures — tsconfig.json referenced the package in compilerOptions.types but it was not installed; package added to package.json

  • Pin ChromaDB to >=0.5.0,<1.0.0 in pyproject.toml — ChromaDB 1.x changed its environment-variable handling, causing import errors and runtime failures in the embedding provider chain; pinning to the pre-1.0 series restores compatibility

Notes

Note: Session indexing was not active for this period. Changes above are sourced from active project memories rather than indexed sessions.

Gotcha: The MCP_SERVER_NAME constant now lives in features/swarm/constants.py. Any pipeline stage or script that imports it from features/team/constants.py will silently fail at runtime — search the codebase for the old import path when adding new pipeline stages.

[2026-03-19]

Changed

  • CloudRelay client shutdown made graceful and idempotent — The disconnect method in cloud_relay/client/_core.py now explicitly cancels and awaits all pending async tasks, suppresses asyncio.CancelledError, and guards each cancellation behind a task.done() check; prevents leaked tasks and unhandled exceptions during relay disconnection

  • Skill deployment workflow formalized — Skill source files now live exclusively under src/open_agent_kit/features/<feature>/skills/<skill>/ as the authoritative template; deployed copies in .claude/, .agents/, and .cursor/ are generated by SkillService which substitutes the {oak-cli-command} placeholder with the project's configured CLI alias; use oak skill refresh or oak upgrade to propagate changes — never raw-copy source templates directly

Notes

Note: Session indexing was not active for part of this period. Changes above are sourced from project architectural memory rather than indexed sessions.

Gotcha: Raw-copying skill source files to .claude//.agents//.cursor/ bypasses placeholder resolution — the deployed skill will contain a literal {oak-cli-command} string instead of the actual alias. Always deploy via oak skill refresh or oak upgrade.

[2026-03-18]

Added

  • Offline observation buffering in Durable Object — The Cloudflare DO now stores pending observations for disconnected nodes in a local SQLite buffer; observations are drained automatically on reconnect via GET /obs/pending?machine_id=X, eliminating data loss for temporarily offline team members
  • RemoteObsApplier for inbound relay observations — New team/sync/obs_applier.py applies observations received from remote nodes to the local activity store, decoupling inbound sync from the outbox worker

Changed

  • Team sync narrowed to observations only — Sessions and batches are no longer relayed to peers; only observations.py and resolution_events.py still enqueue to the team outbox; call sites in sessions/crud.py, batches/crud.py, and activities.py cleaned up; substantially reduces relay bandwidth and simplifies the sync contract
  • TeamSyncWorker renamed to ObsFlushWorker — Responsibility narrowed to flushing buffered observations via relay_client.push_observations(); heartbeat handling fully delegated to CloudRelayClient — see team/outbox/worker.py
  • Cloudflare DO WebSocket routing switched to tag-based lookupacceptWebSocket(ws, [machine_id]) paired with getWebSockets(machineId) replaces the previous reverse-map approach; ws.getTags()[0] provides the machine ID in close handlers with no extra bookkeeping required
  • Cloud relay split into deployed and template copies — Deployed relay now lives at oak/cloud-relay/src/; the template for user deployments lives at src/.../cloud_relay/worker_template/src/; both must be kept in sync on any wire-protocol change
  • Python relay client refactored into three focused modulesprotocol.py (Pydantic wire types), client.py (CloudRelayClient), and base.py (abstract RelayClient/RelayStatus) replace the prior monolithic client module under src/.../cloud_relay/
  • Team API surface trimmed — Only status, members, config, and policy endpoints remain; all auxiliary team management endpoints removed as part of the relay redesign

Removed

  • DB migration v11 — legacy team tables droppedteam_events, team_members, team_api_keys, and pending_joins tables removed from the activity schema; team_outbox is retained; bump CI_ACTIVITY_SCHEMA_VERSION in constants/paths.py to trigger the migration

Notes

Note: Session indexing was not active for part of this period. Changes above are sourced from project architectural memory rather than indexed sessions.

Gotcha: enqueue_team_event has been removed from sessions/crud.py, batches/crud.py, and activities.py. Any code that calls this function will fail at runtime. Only observations.py and resolution_events.py should enqueue to the team outbox.

Gotcha: The DO WebSocket tag pattern requires this.state.acceptWebSocket(ws, [machine_id]) at connection time and this.state.getWebSockets(machineId) for targeted message delivery. The old reverse-map Map<ws, machineId> is no longer maintained — do not reintroduce it.

[2026-03-10]

Changed

  • Remove legacy beta-channel code — Removed all beta-channel branching logic from installer scripts, pipeline stages, and test fixtures; simplifies the release pipeline and eliminates the parallel code paths that were maintained since the beta rollout — Refactor repository to remove legacy beta‑channel code

[2026-03-08]

Added

Changed

Fixed

Notes

Gotcha: The density selector relies on CSS custom properties defined in variables.css for all three density levels. If a new theme omits any of these tokens, components silently fall back to default spacing. Always define all three variants (compact, normal, comfy) when extending the theme.

Gotcha: The FontProvider wrapper was removed from daemon entry points when density support was added. Font persistence is now handled by a standalone local-storage hook — do not re-add FontProvider to new entry points. See main.tsx under features/*/daemon/ui/src/.

[2026-03-07]

Added

  • Swarm feature promoted to beta — The Swarm UI and CLI commands are now surfaced as a beta feature; CI builds pass and the swarm binary is included in the release artifact — Fix CI failures and enable beta swarm binary
  • Migration helper for secrets from .env to per-machine YAML config — A migration utility reads legacy .env swarm tokens and backup paths and writes them into the machine-specific override config (.oak/config.<machine_id>.yaml); subsequent upgrades no longer require manual secret copying — Implement migration helper and unify secret handling in YAML config

Changed

Fixed

[2026-03-06]

Added

Fixed

  • Fix UI build failure caused by uncommitted ui/shared/lib/ directory — Git reported the directory existed on disk but was absent from main, causing a fatal error during Vite's pre-build step before any TypeScript compilation; fixed by committing the directory and its log-constants.ts contents to mainConfigure secure swarm token storage and resolve UI build failures

Notes

Gotcha: If CI_CONFIG_SWARM_KEY_AGENT_TOKEN is missing or empty, requests to swarm MCP endpoints fail silently with a 401/403 — the error surfaces as a generic network failure with no explicit authentication message in client logs. Always verify the agent token is populated before connecting an MCP client to the swarm. See the agent token retrieval logic in swarm/daemon/client.py.

[2026-03-05]

Added

  • Swarm heartbeat advisories and minimum OAK version enforcement — The swarm heartbeat response now carries advisory messages that peers can surface; a new min_oak_version field lets operators enforce a floor version across all swarm members and reject older nodes on connect; includes dedicated health-check endpoints for probing liveness without invoking business logic — Implement swarm heartbeat advisories and min OAK version configuration
  • Full swarm autonomous agent functionality (in progress) — Ongoing work to make the Swarm Analyst agent fully autonomous, enabling it to independently discover peers, fan out tasks, and aggregate results without manual orchestration — Implement full swarm autonomous agent functionality
  • Complete declarative mcp.yaml tool list with tests — The MCP tool registry in mcp.yaml is now fully declarative and accurate; new tests verify the runtime tool registry matches the YAML declaration, preventing silent divergence between config and implementation — Add complete tool list to mcp.yaml and tests
  • Oak skill packaging, export, and benchmark file strategy — The Oak CI skill bundle can now be exported and packaged for distribution; evaluation/benchmark JSON files follow a defined version-control strategy (tracked in oak/ci/history/ benchmarks directory); export tests confirm the bundle shape is stable across builds — Implement Oak skill packaging, export tests, and benchmark file strategy
  • Debug-level logging and rotating log files for swarm daemon — Comprehensive debug logging added throughout the swarm daemon; log output now rotates automatically to prevent unbounded disk growth; a rich terminal-style log-viewer UI — matching the team daemon experience — added to the swarm dashboard — Add debug log level and rotating logs to swarm daemon

Changed

  • Shared log viewer component extracted to ui/shared/ — The terminal-style log viewer is now a single shared React component consumed by both the team and swarm daemon UIs (via the @oak/ui alias); eliminates duplicated log-rendering logic and ensures consistent behaviour and styling across both surfaces — Refactor log viewer into shared component for swarm and team daemons
  • Oak skill template refreshed; schema docs regenerated — The Oak skill template is updated from source and re-exported; references/schema.md, SKILL.md, and all agent system-prompt files regenerated via generate_schema_ref.py to reflect the current schema; the test_schema_version_matches gate in test_skill_service.py now passes cleanly — Update Oak skill template and regenerate schema docs

Fixed

  • Fix swarm daemon restart endpoint failing silently — the SWARM_AUTH_ENV_VAR constant was inadvertently removed during a refactor, so the daemon manager never injected OAK_SWARM_DAEMON_TOKEN into the subprocess environment; the daemon started without a token, causing an auth error and a UI timeout; constant re-added and manager updated to use it when spawning the daemon
  • Fix swarm /fetch endpoint returning None for the function field — the FastAPI route handler omitted the function query parameter from its signature, causing FastAPI to inject None; added function: str = Query(...) to the handler and ensured it is always echoed in the response

[2026-03-04]

Added

Fixed

  • Fix Cloudflare DO hibernation rows_read quota exhaustion — with the WebSocket Hibernation API the DO constructor runs on every wake (not just first start); 12 DDL statements (CREATE TABLE IF NOT EXISTS, etc.) each read sqlite_schema rows, adding up to ~60 rows_read per wake and ~5M rows_read/day—hitting the free-tier ceiling; DDL is now guarded behind a KV-backed _schema_version flag and only executes when the schema version constant changes; applied to both relay-object.ts (SCHEMA_VERSION) and swarm-object.ts (SWARM_SCHEMA_VERSION) — Implement worker activity monitoring and Slack alerts for spike detection
  • Fix upgrade banner never clearing — parse_base_release() in version.py returned None when the version string did not match the expected pattern, causing version_check.py to always evaluate the comparison as "upgrade required"; updated the parsing regex to handle the new semantic-version format and added a fallback that treats an unparsable version as equal to the current base release — Refactor team feature layout, update imports, rebuild UI and daemon
  • Fix UI build failures after restructure — package.json scripts in both the team and swarm daemon UIs referenced a non-existent tsconfig.app.json path; additionally, the shared TypeScript config ui/shared/tsconfig.json was deleted during the refactor while downstream tsconfig.app.json files still extended it, causing tsc -b to fail with "File not found"; restored the shared config with correct compiler options and updated all extends paths — Refactor team feature layout, update imports, rebuild UI and daemon
  • Fix wrangler subprocess using wrong working directory for worker deployment — worker_deploy_shared.py set cwd to the swarm root rather than the worker_template/ subdirectory, causing Node to fail to resolve wrangler-dist/cli.js; run_cwd now defaults to the worker template path — Add deploy subcommand, start daemon with URL output and config validation
  • Fix OTel Codex agent silently dropping telemetry — the protocol field was either missing or using an unsupported value; confirmed correct config requires protocol = "binary" nested under otel.exporter.otlp-http in the Codex TOML template — Configure OTel agent for binary encoding usage
  • Fix empty federated search result cards in Team UI — the use-network-search.ts hook destructured the cloud-relay API response using the key results, but the endpoint returns data under data; every federated result was rendered with an undefined payload, producing blank cards; fixed by updating the destructuring and normalising the shape before passing to the card component — Fix empty federated search result cards in Team UI search rendering
  • Fix custom domain not honoured during Team Relay deployments — after the repository restructure the cloud_relay.py deployment route no longer wrote CLOUD_RELAY_RESPONSE_KEY_CUSTOM_DOMAIN to the status response, causing the UI to silently fall back to the default workers.dev domain even when a custom domain was configured; the missing write was restored — Fix custom domain not honored during Team Relay deployments

Changed

  • CLI namespaces reorganized to match new feature structure — daemon lifecycle commands now live under oak team (e.g., oak team start/stop/restart); codebase intelligence commands under oak ci (e.g., oak ci index/search/config); both namespaces expose oak team mcp and oak ci mcp for backward compatibility — Refactor codebase intelligence to team feature structure
  • Extract shared agent runtime route module — duplicated agent-creation, run-polling, and log-streaming logic was present in both the team and swarm daemon route layers; consolidated into a single shared module so both daemons are thin consumers; ensures consistent response schemas and error handling across the two surfaces — Refactor agent runtime logic into shared route module

Notes

Gotcha: The Cloudflare Durable Object constructor re-runs on every hibernation wake, not just the first start. Any DDL executed unconditionally in the constructor counts toward rows_read quota on every wake. Always gate DDL behind a KV-backed schema-version flag (see relay-object.ts SCHEMA_VERSION / swarm-object.ts SWARM_SCHEMA_VERSION) and bump the constant only when the schema actually changes.

Gotcha: The OTLP protocol field is case-sensitive and must be exactly "binary" or "json". An unsupported value or wrong casing silently disables the exporter with no error log. Additionally, the field must be nested as otel.exporter.otlp-http.protocol — a separate [otel.exporter.otlp-http] TOML table is no longer parsed by the current Codex runtime. See otel_config.toml.j2.

Gotcha: The swarm daemon's agent state is held in memory only (state.py). A daemon restart loses all current agent statuses with no disk or database fallback. Plan for stateless restarts or implement persistence before relying on swarm state in production.

Gotcha: The wrangler.toml.j2 template does not inject custom_domain into the routes section unless the variable is explicitly forwarded to the Jinja context via render_wrangler_config. After the restructure refactor this argument was dropped, silently deploying workers with the default workers.dev domain even when a custom domain was set. Always pass custom_domain through the template context and verify domain resolution in the deployment validation step.

Gotcha: Federated nodes return HTTP 200 with an empty array when they have no matching results — not a 404 or error sentinel. Any UI hook that treats a non-empty response array as the success condition (like the pre-fix use-network-search.ts) will silently render empty cards. Normalise both the shape and the empty-array case when consuming federated search responses. See use-network-search.ts and the cloud-relay client.py.

[2026-03-03]

Added

Fixed

  • Fix GitHub Actions release step failing on stale release tag — a stale release/tag left over from a prior failed run blocked the "Create GitHub Release" action; deleting the stale tag restored the release pipeline — Fix GitHub Actions release tag error by deleting stale release
  • Fix Oak upgrade CLI path resolution for skills and MCP server commands — the upgrade command incorrectly resolved skill and MCP server entry points to main.py rather than the correct command path, causing upgrades to silently wire the wrong binary — Fix Oak upgrade CLI command path resolution for skills and MCP servers
  • Fix hanging auto-refresh on custom agent task runs — the daemon registry aborted silently when project_config was absent for a named agent (log: No project config for agent 'analysis'), causing route handlers to throw and the UI polling loop to stall indefinitely; a defensive fallback now loads an empty default config and emits a clear warning, allowing the daemon and UI to continue normally — Debug auto‑refresh dismissal logic for custom agent tasks

Changed

Notes

Gotcha: The cloud-relay UI auto‑start toggle reads team.cloudRelay.autoStart from local component state, which is only populated when GET /cloud-relay/status is queried on mount. Any extension to the start/deploy route that omits auto_start from its response will cause the UI to always show "Auto‑start: off". See cloud_relay.py and TeamConfig.tsx.

Gotcha: Rapid consecutive policy edits (e.g. toggling federated_tools quickly in the UI) can trigger a WebSocket reconnect storm — update_team_policy() calls request_reconnect() on the relay client, which relies on a backoff loop that may not be robust under aggressive saves. Debounce policy updates on the frontend to avoid spin-up loops. See cloud_relay/client.py.

[2026-03-02]

Added

Fixed

Changed

Notes

Gotcha: generate_schema_ref.py must be run after any schema change and before the test suite — it writes schema.md; omitting it causes tests to read stale schema data. The script is not invoked automatically by the build pipeline.

Gotcha: Always bump CI_ACTIVITY_SCHEMA_VERSION in constants/paths.py when adding a migration. A missed bump leaves the database at an intermediate schema version and causes subsequent migrations to fail.

[2026-03-01]

Added

Fixed

Notes

In Progress: Cloud relay WebSocket connections are rejecting with a 401 during team sync; root cause under active investigation — Debug Cloud Relay WebSocket 401 for Team Sync commit

Gotcha: The cloud relay auth token is held only in memory on the server side — no persistent storage. Any new node connecting after a daemon restart will receive a 401 with no detail. Re-deploy the relay via Team → Connectivity to reissue the token.

[2026-02-28]

Added

Fixed

Changed

Notes

Gotcha: TeamStatus.tsx expects the backend to return a status field; a missing or mistyped field causes the component to silently render an empty status with no error. Add a defensive default or null-check when extending the /team endpoint.

Gotcha: The outbox worker does not buffer events locally — if the server is offline when a sync is attempted, the payload is discarded immediately. Changes made while the server is unreachable are lost until a new sync cycle runs after reconnection. See team/outbox/worker.py.

[2026-02-27]

Added

Notes

Gotcha: The Join flow requires the server's auto-generated machine key to be present in the config override file (config/team.py). A missing or corrupted file causes join requests to be rejected with a 404 from the relay. Verify the file exists before testing the flow.

Gotcha: The Join approval flow is synchronous — the daemon writes approval immediately to SQLite but the client UI does not poll for status. Users see no feedback until a manual refresh.

Gotcha: Do not use the Join flow on the machine acting as the team server. This causes authentication conflicts. Client machines must join from a separate device using a member API key generated on the server.

[2026-02-26]

Added

Fixed

Changed

Notes

Gotcha: Oak Teams sync stores events as plain strings in SQLite — team keys are indexed but not hashed at rest. Secure the daemon database (.oak/ci/activities.db) with appropriate file permissions.

Gotcha: The persistent team-status banner polls the daemon's enriched /team endpoint, which requires the X-OpenAgent-Team-Key header. A missing or invalid key returns a generic 401 with no detail — verify the key is set in .oak/config.yaml.

Gotcha: SESSION_SECRET must be present in the environment where Cursor hooks execute. If absent, the hook drops the session silently and logs a [DROP] message. Check .cursor/hooks.json environment configuration if Cursor sessions are not appearing in the activity log.

Gotcha: Oak Teams API keys serve two purposes — loopback (internal daemon communication) and user-generated (external access) — both stored in the same SQLite table. A missing unique constraint or column mismatch can cause silent key duplication. Inspect team/server/auth.py if duplicate loopback keys appear after a daemon restart.

[2026-02-25]

Added

Changed

Notes

Note: The JWT hardening and FTS sanitization in this entry are the first concrete implementation output from the security remediation roadmap planned earlier in the day. Remaining tiers are tracked in the roadmap produced by the planning session.

[2026-02-24]

Added

Changed

  • Upgrade command now launches in a detached subprocess from daemon UI — a new helper spawns oak upgrade as a detached process so the daemon UI remains responsive during upgrades rather than blocking on the CLI subprocess — Implement detached upgrade command helper for daemon UI

Fixed

  • Fix daemon_client.py path construction causing FileNotFoundErrordiscover_daemon used an unresolved relative rel_path when locating the daemon port file; now resolves the full path via Path(project_root).resolve() / rel_path and returns None gracefully when the file is absent — Implement automated smoke‑test for oak daemon and clean up artifacts
  • Fix _run_upgrade_pipeline type errors in restart.pyPath type was not imported and the run_in_executor call passed a plain dict instead of the required UpgradePlan instance; both corrected to resolve Ruff static-analysis errors and prevent runtime type mismatches — Implement detached upgrade command helper for daemon UI
  • Fix activity route registration typo and missing authentication — @router.ge decorator typo prevented the endpoint from registering with FastAPI, and activity routes lacked the shared Authorization header dependency used elsewhere in the daemon — Implement tool usage hooks and session summaries for ACP flow

Notes

Gotcha: ACP focus switching injects a system-prompt override at session-config time. Mid-conversation agents will not retroactively reinterpret earlier messages under the new template — focus changes take effect on the next message boundary only.

Gotcha: The ACP smoke-test expects the daemon's activity store directory (~/.oak/activity_store) to exist and be writable before tests run. If the smoke-test exits with code 1, verify the directory exists with correct permissions and that daemon/config.py points to that path.

[2026-02-23]

Added

Changed

  • Upgrade banner prompt text made more descriptive — the UI now displays a clearer label when an automatic update is detected and ready to apply, replacing the previous terse restart prompt — Update Upgrade Prompt Text with Descriptive Label

Fixed

Notes

Note: The ACP server is shipped as an optional dependency (acp extra in pyproject.toml). The core OAK distribution remains lightweight; install with pip install open-agent-kit[acp] to enable editor ACP integration.

Gotcha: The acp package must be installed in the same virtual environment as OAK. If the daemon raises ModuleNotFoundError: No module named 'acp' at startup, verify the package is present (pip show acp) and that the daemon is running from the correct environment.

Gotcha: The ACPIntegrations component context provider (AcpIntegrationContext) is created and consumed within the same file and is not exported. Composing ACP integration state into other UI pages requires either lifting state to a shared context or extending the export surface.

[2026-02-22]

Added

Changed

Fixed

Notes

Gotcha: resolve_main_repo_root() previously assumed .git was a directory. Inside a worktree it is a plain file containing gitdir: <path>. Any code that calls this helper must be tested in both regular checkout and worktree contexts; imports also require the repository root on PYTHONPATH since worktrees do not automatically inherit the parent repo's module search path.

Gotcha: The Team Member filter groups sessions by user identity, not by machine. If two developers share the same Git username the filter will merge their sessions into one group. The machine-level source_machine_id field is still available in the SessionItem payload for tooling that needs it.

Gotcha: The upgrade banner's hard-coded UI_COMMAND constant caused it to show "oak" even when users ran "oak-dev" or another alias. After the fix the banner reads config.command_alias at render time — ensure the daemon is restarted after changing your CLI alias so the config propagates.

[2026-02-21]

Added

Fixed

  • Fix ci_project_stats always reporting zero unique files and zero memory count — get_stats() was missing unique_files and memory_count keys in its return dict; count_unique_files also skipped counting when commits had no files. Both fixed in management.py and operations.pyFix CI projects stats agent project count bug
  • Fix hover styles disappearing on navigation bar components — Tailwind group-hover utilities were not triggering because parent elements were missing the group class after a recent refactor — Debug missing hover styles in navigation bar components
  • Fix governance plugin error caused by missing or misconfigured Oak governance settings — security guidance plugin hook was loading unconditionally at startup and failing when governance was not enabled in the target project — Configure Oak governance settings to fix plugin error

Notes

Gotcha: The Tailwind group-hover utility requires the parent element to carry the group class. Navigation components that lost this class during a refactor will silently drop all hover effects — check the rendered DOM if hover styles stop working after restructuring layout components.

Gotcha: The security guidance plugin registers its hook via hooks.json and loads unconditionally at agent startup, regardless of whether governance is enabled in the host project. Projects without Oak governance configured will see a runtime error. Set governance.enabled: false in the project's Oak config, or ensure the plugin is only installed in governed projects.

[2026-02-19/20]

Added

Changed

Fixed

  • Fix ci_project_stats always reporting zero unique files and zero memory count — get_stats() was missing unique_files and memory_count keys in its return dict; count_unique_files also skipped counting when commits had no files. Both fixed in management.py and operations.pyFix CI projects stats agent project count bug
  • Fix critical executor bug in _get_effective_execution() causing incorrect task dispatch — standardized analysis task prompts as part of the same cleanup — Fix critical executor bug and standardize analysis task prompts
  • Fix missing Logs tab in Daemon UI navigation — tab was silently dropped during a left-nav reorder — Fix missing logs tab in Daemon UI navigation
  • Fix session lineage auto-linking after plan execution — child sessions now correctly link to parent when executing a plan, resolving orphaned session chains — Fix session lineage auto-linking in Claude Code
  • Fix Cursor plan capture detection — plan files created by Cursor are now properly detected and linked to sessions in the codebase intelligence system — Fix Cursor plan capture detection in codebase intelligence
  • Fix governance hook event casing mismatch — HOOK_EVENT_PRE_TOOL_USE constant was kebab-case (pre-tool-use) but Claude Code sends PascalCase (PreToolUse), causing deny responses to never apply. Now normalizes both sides for comparison — Implement CI governance sub-module with deny mechanism
  • Fix CLI help text listing rfc as a primary command when it's agent-only — help output now accurately reflects the command hierarchy with oak ci as the primary CI entrypoint — Fix CLI help text accuracy and command separation
  • Fix MCP server plan resolution and tool call handling — plans now show resolved state correctly during polling, and tool call descriptions are clearer for debugging — Fix plan resolution and tool call handling in MCP server
  • Fix "today" filter showing incorrect results due to timezone mismatch — date filtering now correctly handles timezone differences between server and client — Fix date filtering and user identity issues in session summaries
  • Fix VS Code Copilot hook crashes — centralized hook formatting and fixed schema validation errors that caused the Copilot integration to crash after recent refactors — Fix VS Code Copilot crash by centralizing hook formatting, Fix VS Code Copilot schema crash after refactor, Fix undefined hook error in VS Code Co‑Pilot integration
  • Fix early migration order to refresh agent list — migrations now run in correct order to ensure the agent list is refreshed before the upgrade pipeline processes it — Fix early migration order to refresh agent list for upgrade pipeline
  • Fix Oak daemon upgrade error handling — raw error messages are now hidden from users during upgrades, replaced with user-friendly messaging — Fix Oak daemon upgrade error handling to hide raw errors
  • Fix "Compact All" button leaving ChromaDB in locked state — the button now triggers a daemon restart after deleting the collection, ensuring the database is cleanly reopened in a fresh process context without manual intervention — Fix Compact All button to restart daemon after deletion
  • Fix session summary title generation failing for non-reasoning models — the title extraction regex now handles models that don't emit chain-of-thought reasoning, preventing empty or malformed titles — Fix session summary title generation for non‑reasoning models
  • Fix environment and dependency resolution issues affecting Agents SDK and Oak CLI installations — improved path handling and dependency isolation to prevent conflicts between editable installs and tool installs — Fix environment and dependency issues for agents SDK and Oak CLI
  • Fix Homebrew tap build failures and update installation documentation to reflect brew install goondocks-co/oak/oak-ci as the recommended macOS install method — Fix Homebrew tap and update Oak CI installation docs
  • Fix daemon self-restart failing after Homebrew upgrade — sys.executable pointed to the old deleted Cellar path, causing FileNotFoundError. Now uses /bin/sh -c "sleep N && oak ci restart" which always resolves to the current version on $PATHImplement daemon version mismatch detection and recovery
  • Fix Homebrew formula PyPI CDN propagation race condition — brew install could fail if the PyPI simple index hadn't propagated the new version yet. Formula post_install now retries pip install 5 times with 30s backoff, and the tap workflow uses pip download --no-deps with 20 retries over 10 minutes — Fix Homebrew tap and update Oak CI installation docs
  • Fix session auto-linking selecting stale parent — find_linkable_parent_session now filters by project ID and returns the most recent eligible session, preventing child sessions from linking to unrelated older sessions across projects
  • Fix Cloud Relay page losing custom domain on refresh — the /api/cloud/status endpoint now includes custom_domain in its payload so the UI consistently uses the saved domain after page reload
  • Fix Cloud Relay spurious error toast on WebSocket connect — the onError handler now only sets error state when the event payload contains an actual error message, suppressing false toasts on normal connection establishment
  • Fix plan_detector.py default argument causing FileNotFoundErrorknown_plan_file_path now defaults to an empty string with a guard that skips file I/O on empty input, preventing test-suite failures
  • Fix Cloud Relay worker deployment missing wrangler.jsonc — scaffolding now generates a minimal wrangler.jsonc with worker name, compatibility date, and main script path so npx wrangler deploy can locate the entry point automatically

Notes

Note: The Brain Maintenance Agent uses a memory_write flag to gate write access to the memory store. Without this flag set, the agent runs in read-only/analysis mode. Health reports persist to oak/insights/ as JSONL files so they survive daemon restarts and can be queried without a database.

Gotcha: The ci_project_stats tool reported 0 unique files when any commit had an empty file list — the old if not commit.files: continue guard prevented counting files from other commits. After the fix, counts are aggregated across all commits using a set for deduplication. Agents that cached the old zero values should call ci_project_stats again to get accurate counts.

Note: The unified upgrade/restart banner consolidates two previously overlapping UI states — update_available (version mismatch requiring daemon restart) and upgrade_needed (schema/config migrations requiring oak upgrade) — into a single banner component with distinct messaging for each state.

Note: The shared .agents/skills/ directory is the new canonical location for skills shared across multiple agents. Per-agent skill copies are no longer installed during oak upgrade; agents now resolve skills from the shared directory at runtime.

Note: The power management state machine for the daemon UI introduces a usePowerState hook that centralizes polling intervals. Components that previously polled at fixed intervals now derive their polling rate from the shared power state, reducing CPU and network overhead during idle and sleep states.

Gotcha: Governance hook event names use different casing across agents — Claude Code sends PreToolUse (PascalCase), but constants may be defined as pre-tool-use (kebab-case). The governance engine now normalizes all event names with .lower().replace("-", "").replace("_", "") to handle all variants.

Gotcha: Session summaries were previously stored as memory_observations with memory_type='session_summary'. After the v5→v6 migration, they live in sessions.summary. Backup restore includes a backfill function (_backfill_session_summaries_from_observations) to handle legacy backup files that still use the old format.

Gotcha: Governance audit events are stored in governance_audit_events and are now included in team backups. If restoring a backup from before governance was implemented, the audit table will be empty but functional.

Gotcha: SQLite's VACUUM command cannot run within a transaction context — attempting to do so raises OperationalError: cannot VACUUM from within a transaction. DevTools maintenance operations now explicitly close any active transaction before running VACUUM.

Gotcha: ChromaDB delete operations can fail silently and leave orphaned entries. The new "Clear Orphan Entries" button in DevTools identifies embeddings that lack corresponding SQLite records and removes them with retry logic to handle transient failures.

Gotcha: The version mismatch detection writes a stamp file (.oak/ci/cli_version) only when the CLI runs, so it adds no overhead to normal operation. However, the restartDaemon API call must be awaited before updating the UI — otherwise stale data may be displayed.

Gotcha: When automatic built-in task installation is disabled, any missing built-in task files will cause runtime errors if agents reference them. Ensure required tasks are present in oak/agents/ before running the pipeline, or rely on the registry's built-in loader.

Gotcha: The project name in the browser tab is sourced from window.projectName injected by the server. If this variable is missing or undefined, the title defaults to just the static suffix.

Gotcha: After the hooks-local-only migration, hook config files (e.g., .cursor/hooks.json, .windsurf/hooks.json) are gitignored and exist only on machines with Oak installed. Hooks already degrade gracefully when files are absent, so contributors without Oak are unaffected — but developers must run oak upgrade to regenerate local hook files after a fresh clone.

Gotcha: The daemon self-restart route must not use sys.executable because Homebrew upgrades delete the old Cellar path. If you see FileNotFoundError during restart, verify that the oak binary on $PATH points to the current version (which oak).

Gotcha: The "Compact All" button in DevTools deletes the ChromaDB collection, but ChromaDB holds file locks that persist until the process exits. Without a daemon restart, subsequent re-indexing fails with database lock errors. The fix triggers an automatic restart after deletion to cleanly reopen the database.

Gotcha: VS Code Copilot hook crashes were caused by schema validation running before hook formatting centralization. If you see hook errors after an upgrade, run oak upgrade to regenerate hook configurations with the corrected schema handling.

Gotcha: Inline plan detection uses heuristic response patterns (e.g., numbered steps, "Implementation Plan" headers). False positives are possible for assistant responses that resemble plans but aren't. The detector favors recall over precision — plans are better captured twice than missed.

Gotcha: Power state idle detection requires a fallback to start_time when last_hook_activity is None. Without this, the daemon stays in ACTIVE state forever if no hooks fire after startup (e.g., daemon starts and user walks away). The fix uses last_activity = daemon_state.last_hook_activity or daemon_state.start_time.

Gotcha: Resolution events are stored separately from observations in the resolution_events table. When backing up/restoring, both tables must be synchronized — if resolution events are missing, observations may incorrectly appear as unresolved on the target machine.

Gotcha: Machine-specific source ID filters in background processing queries prevent cross-machine data leakage but require the source_machine_id column to be populated. Observations created before this column existed will have NULL source IDs and may be filtered out unexpectedly.

Gotcha: The store_resolution_event helper requires the observation ID and action status to be passed explicitly. Forgetting to provide these arguments leads to silent failures or incorrect event logging.

Gotcha: Observation lifecycle status defaults to active. When querying memories via ci_memories or ci_search, use status=active for current knowledge and include_resolved=true only for historical documentation (e.g., changelogs). Resolved observations represent what was true, not what is true.

Gotcha: Session origin types (planning, investigation, implementation, mixed) are inferred from file changes and code patterns. Planning-originated observations are more likely to become stale after implementation work completes — the auto-resolve system uses semantic similarity to detect when newer observations supersede older ones.

Gotcha: The batch processing size (now 50 items per cycle) is a magic number that was refactored into a configurable constant. If processing appears slow, check that the batch size hasn't been inadvertently reduced, and ensure parallel processing is enabled to avoid database locking issues.

Gotcha: Ollama often uses a smaller default context window than LM Studio for the same model, causing output format instructions at the end of long prompts to be truncated. This leads models to return JSON (e.g., {"summary": [...]}) instead of plain text. The _unwrap_json_summary() function in summaries.py handles this defensively.

Gotcha: Cloud relay WebSocket connections require an active worker deployment to validate. The connection handler checks for worker availability before establishing the WebSocket, and errors are shown only when new actual errors occur rather than showing transient states.

Gotcha: The title_manually_edited flag prevents LLM-generated titles from overwriting user edits. However, if a user clears the title field and saves, the flag remains set — the title won't auto-regenerate until the flag is explicitly cleared.

Gotcha: Custom domain provisioning for Cloud Relay requires the domain zone to reside in the user's Cloudflare account. If the zone is managed elsewhere, automatic DNS/SSL provisioning will fail silently and the worker will fall back to the default workers.dev URL.

Gotcha: UI state for saved custom domains is not persisted across page refreshes — users may need to re-save the domain after refreshing the Cloud Relay settings page.

Gotcha: Content-hash deduplication compares the full text of observations before insertion. Two observations with identical content but different metadata (e.g., different session_id or memory_type) are treated as duplicates — only the first is stored. If you need to record the same insight across multiple sessions, vary the observation text slightly or rely on session-level attribution via the session_id metadata.

Gotcha: Session-linking microsecond precision — SESSION_LINK_IMMEDIATE_GAP_SECONDS and SESSION_LINK_STALE_GAP_SECONDS thresholds are defined in whole seconds, but timestamp comparisons include microseconds. Sessions that end within the same second as a new one starts may be misclassified as stale or immediate depending on microsecond ordering. This is most visible under rapid "clear context and continue" operations.

Gotcha: The restore API does not automatically generate governance audit entries for restored data. If your workflow requires a full audit trail across restores, trigger audit logging manually after a successful restore.

[1.0.3] - 2026-02-10

Added

Fixed

Notes

Gotcha: Homebrew formula for oak-ci uses python -m venv directly (not virtualenv_create) because Homebrew's helper passes --without-pip. Key details: (1) venv.pip_install uses --no-deps so deps won't install — the formula uses system libexec/"bin/pip", "install" instead, (2) homebrew-pypi-poet requires setuptools<81 on Python 3.13, (3) bin.install_symlink libexec/"bin/oak" is needed to expose the binary.

Gotcha: The removal logic now distinguishes between OAK-managed files (agent task YAMLs, daemon.port) and user-generated content. If custom files are placed in oak/agents/ with names matching the agent-*.yaml pattern, they may be incorrectly treated as OAK-managed and removed during oak remove.

Gotcha: If the --python flag is omitted when installing with pipx or uv, Oak may be installed against an unintended Python interpreter (e.g., Homebrew's Python 3.14), leading to runtime errors from incompatible dependencies like chromadb and pydantic.

[1.0.2] - 2026-02-09

Added

Changed

Fixed

Improved

Notes

Gotcha: .oak/state.yaml tracks applied migration names. If migrations are removed from the codebase but their names remain in state.yaml, the migration runner may attempt to reference non-existent modules, causing ImportError or silent failures during startup. After a clean release, ensure state.yaml is reset or excluded from version control.

Gotcha: The install script must handle both user-local and system installations. On macOS, ~/.local/bin may not be on PATH by default — the installer now appends it to the appropriate shell profile (.zshrc, .bash_profile), but users with custom shell setups should verify manually.

Gotcha: GitHub issue templates must be placed in .github/ISSUE_TEMPLATE/ with the .yml extension. A missing or misnamed file will silently not appear in the issue creation UI.

[Previous] - pre-1.0.2

Added

Changed

Fixed

  • Fixed MCP server resilience to daemon restarts with token refresh, guard reset, and 3-attempt retry loop — Debug CI daemon API hook integration and auth headers
  • Fixed UI agent resume button not appearing for CodeX sessions after model name format change to GPT-5.3/codexFix UI agent bug and add Gemini resume CLI command
  • Fixed Gemini CLI not recognizing resume command with space-dash-space variant — Fix UI agent bug and add Gemini resume CLI command
  • Fixed /backup/last endpoint returning empty 200 instead of 404 when no backup exists
  • Fixed React error #310 in SessionDetail.tsx caused by hooks called after early returns
  • Fixed MCP server 401 errors by adding daemon token file reading and Bearer header injection
  • Fixed Windsurf agent freeze caused by show_output hooks blocking event loop — Fix Windsurf agent freeze by removing show_output hooks
  • Fixed ChromaDB session cleanup leaving orphaned embeddings after SQLite deletion — Add cleanup logic for embedded ChromaDB sessions
  • Fixed /devtools/compact endpoint raising NameError due to undefined variable reference — Debug daemon devtools failure after corrupted state cleanup
  • Fixed built-in Oak tasks not flagged as is_builtin in agent registry, causing incorrect UI display
  • Fixed prompt_batches table missing created_at column causing query failures
  • Fixed cascade assistant infinite loop when lastSelectedCascadeModel field is empty in Windsurf settings
  • Fixed activity routes missing from FastAPI application causing 404 errors on /activity/... endpoints
  • Fixed related session links not navigating in daemon UI and link-session modal requiring double-click — Fix related session links and modal double‑click bug
  • Fixed sharing configuration placed on wrong page and stabilized flaky async tests — Fix sharing configuration placement and stabilize test suite
  • Fixed uv tool install silently destroying editable installs by detecting PEP 610 direct_url.json and conditionally passing -eConfigure CI backup directory via environment variable
  • Fixed missing .oak/agents/ directory after oak init causing downstream failures — Fix missing agents directory after oak init
  • Fixed hooks.py using Path.cwd() instead of project root, causing silent data loss when Claude Code changes working directory — see hooks.py
  • Fixed get_backup_dir resolving relative to cwd instead of project root, causing misplaced backups in tests — see backup.py
  • Fixed session schema drift: SQL queries referencing renamed sessions.session_id and removed started_at_epoch columns — see sessions.py
  • Fixed SessionLineage query running when sessionId is undefined after refactor removed enabled guard — see SessionLineage
  • Renamed agent tasks now correctly installed during upgrade (name-based lookup replaced with stable identifiers) — Implement upgrade logic for built‑in task templates
  • Fixed Vite configuration causing UI build failure — Configure minimal Vite config to fix UI build
  • Fixed UI build error related to dependency injection setup — Fix UI build error and outline DI plan
  • Fixed filter chips in Logs page clearing entire log list instead of filtering — see Logs.tsx
  • Fixed indexStats variable not defined in Dashboard.tsx causing TypeScript build failure — see Dashboard.tsx
  • Fixed session summary not rendering as Markdown in MemoriesList component — see MemoriesList.tsx
  • Fixed DevTools maintenance card layout wrapping below header instead of beside it — see DevTools.tsx
  • Fixed Daemon UI bugs and added developer tools — Fix Daemon UI bugs and add developer tools
  • Fixed failing hook import in CI test suite — Debug failing hook import in CI test suite
  • Fixed plan capture workflow for Claude sessions — Configure plan capture workflow for Claude sessions
  • Fixed MCP upgrade dry run inconsistencies — Debug MCP Upgrade Dry Run Inconsistencies
  • Fixed Claude code causing 100% CPU hang — Debug Claude code causing 100% CPU hang
  • Fixed agent executor behavior after refactor — Fix agent executor behavior after refactor
  • Fixed CLI crash from AttributeError: 'list' object has no attribute 'items' caused by registered_groups being overwritten with a list during refactoring
  • Fixed failing test test_plan_service.py::test_create_plan_from_issue by removing call to non-existent issue provider
  • Fixed system health card truncating summarization model name by replacing hard-coded slice with CSS text-overflow: ellipsis
  • Fixed dashboard displaying incorrect session count by using count_sessions() instead of recent sessions count
  • Fixed orphaned memory entries by adding cascade delete for dependent observations
  • Fixed upgrade service leaving empty parent directories after settings file deletion
  • Fixed orphan-recovery logic not detecting plans due to PROMPT_SOURCE_PLAN constant mismatch
  • Fixed CI backup filename leaking full path by using privacy-preserving hash — Fix CI backup filename privacy bug
  • Fixed agent executor crash on unexpected errors by adding broad exception handling — see executor.py
  • Fixed CI process hanging when MCP configuration is missing by adding defensive check and fallback — see .mcp.json
  • Fixed macOS hook hang caused by missing timeout utility by using portable alternative — see oak-ci-hook.sh
  • Fixed startup indexer globbing entire home directory due to unescaped path characters
  • Fixed daemon startup failure caused by sleep receiving non-numeric argument
  • Fixed TypeScript build error from missing Switch component export — see Schedules.tsx
  • Fixed duplicate parent suggestions by checking existing linked sessions before proposing
  • Fixed VectorStore.find_similar_sessions method signature mismatch with call site
  • Fixed rebuild_index endpoint type error when stores are None by adding explicit dependency injection
  • Fixed session lineage not displaying by wiring useSessionLineage hook result into component render
  • Fixed agent removal not cleaning up plugin directory and opencode.json by adding deletion logic to pipeline stages
  • Fixed plan file not being captured by adding postToolUse hook entry
  • Fixed skill upgrade detection only checking first agent by iterating over all configured agents
  • Fixed MCP tools endpoint returning empty response due to malformed constant definition — see mcp_tools.py
  • Fixed upgrade service only reporting Claude hook updates by rewriting detection loop to iterate all agent directories
  • Fixed memory listing UI incorrectly showing plan entries by adding type filter
  • Fixed UI build failure caused by missing react-scripts dependency
  • Fixed CI plan capture and Markdown UI rendering issues — Fix CI plan capture and Markdown UI rendering
  • Fixed backup and restore feature completion status — Debug backup and restore feature completion status
  • Fixed /plans API endpoint returning 500 error when no plans exist by ensuring get_plans() always returns a list — see store.py
  • Fixed session summary endpoint returning empty strings by adding missing Summarizer.process_session call
  • Fixed RetrievalEngine not being exported correctly from its package, causing ImportError — see retrieval/__init__.py
  • Fixed race condition where concurrent hook calls could corrupt in-memory state by adding thread-safety around state mutations
  • Fixed off-by-one error in PromptBatchActivities.tsx that skipped rendering the last activity
  • Fixed backup process not triggering recomputation of computed_hash, leading to stale backups — see backup.py
  • Fixed parent_session_id foreign key not being re-established during backup restore
  • Fixed deletion routine causing orphaned Chroma embeddings by reordering operations to delete from Chroma before SQLite commit
  • Fixed watcher showing inflated file counts after deletions by adding watcher_state.reset() after full rescan — see watcher.py
  • Fixed batch status being set to 'completed' before patches were applied, causing the loop to skip processing
  • Fixed first prompt in session incorrectly marked as plan by checking prompt text against known patterns
  • Fixed duplicate plans appearing by adding session_id filter to get_plans query
  • Fixed internal server error caused by missing newline before ActivityStore class definition
  • Fixed legacy null-check for source_machine_id column that caused unnecessary conditional logic in restore
  • Fixed summary capture activity and Cursor hook payload handling — Add summary to capture activity and fix cursor hook
  • Fixed notification deduplication dropping events due to timestamp suffix in event key — see notifications.py
  • Fixed Claude Code transcript parsing to handle nested message format ({type: "assistant", message: {...}}) — see transcript.py
  • Fixed notification installer guard logic incorrectly skipping script generation — see installer.py
  • Fixed CI command package missing submodule exports causing import failures — see ci/__init__.py
  • Fixed OTEL route accessing manifest as dict instead of Pydantic model — see otel.py
  • Fixed response summary not captured when user queues a new message while Claude is responding (interrupt bypasses Stop hook) — added fallback capture in UserPromptSubmit — see hooks.py
  • Fixed stale session recovery race condition where resumed sessions were immediately marked stale due to empty prompt batch — see sessions.py
  • Fixed backup restoration failing when run from different working directory due to relative path check — see backup.py
  • Fixed SQL query referencing non-existent parent_reason column in sessions table — see hooks.py
  • Fixed syntax errors in hooks.py caused by incomplete edits leaving stray characters — see hooks.py
  • Fixed notification config template auto-generating unwanted language field — see notify_config.toml.j2
  • Fixed prompt batch finalization logic duplicated across routes by extracting to shared helper — see batches.py

Improved

  • Session URLs in changelog now link directly to daemon UI for better traceability
  • Executor now uses runtime lookup of daemon port for greater deployment flexibility
  • Hook timeout increased to reduce flaky failures during heavy local LLM workloads
  • Session end hook now auto-generates pending titles from session summary for better discoverability
  • Codex VS Code extension OTel configuration validated — project-local .codex/config.toml is syntactically correct but extension only reads global config — Configure OTel settings for Codex VS Code extension
  • Quality gate (make check) cleaned up: removed blocker comments and verified full test suite passes — Refactor blocker comments and run full quality gate check

Notes

Gotcha: The Codex VS Code extension only reads the global codex.toml for OTel settings — project-local .codex/config.toml is ignored by the extension. Place OTel configuration in the global file if targeting the extension.

Gotcha: Backup directory paths configured via OAK_CI_BACKUP_DIR must be absolute. Relative paths silently resolve to cwd, which can produce unexpected file locations if the process changes directories.

Gotcha: The uv tool install commands in feature_service.py and language_service.py previously destroyed editable installs. If you experience stale daemon assets or Path(__file__) resolving to site-packages, verify with oak --python-path -c "import open_agent_kit; print(open_agent_kit.__file__)" — the path must contain your source tree.

Gotcha: Agent YAML files must be placed in oak/agents with the exact same filename as the built-in version; otherwise the registry will not find them and the default task will be used. A missing or renamed file silently falls back to the core definition.

Gotcha: The daemon port file is now expected at oak/ instead of oak/ci/. Documentation or tooling referencing the old path will fail to load runtime configuration.

Gotcha: The UpgradeService performs a dry-run check first. Running oak upgrade compares template files against the latest version and reports "already up to date" if no differences are found. It does not trigger the asset build step — run oak build explicitly after modifying skills.

Gotcha: The next auto-backup time is calculated as last_backup + interval. If no previous backup exists, an immediate backup is scheduled. This approach avoids cron complexity but may drift if backups take longer than expected.

Gotcha: Astro's output: 'static' mode triggers prerendering for all routes without dynamic data. Ensure the docs site has no server-only routes before enabling this optimization.