Skip to content

fix: onboarding blocking#88

Open
webdevtodayjason wants to merge 1 commit intomainfrom
fix/onboarding-block-v2
Open

fix: onboarding blocking#88
webdevtodayjason wants to merge 1 commit intomainfrom
fix/onboarding-block-v2

Conversation

@webdevtodayjason
Copy link
Copy Markdown
Contributor

@webdevtodayjason webdevtodayjason commented Mar 29, 2026

Fix.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Jobs Board and Org Chart widgets to the operations dashboard
    • Expanded CI platform coverage with new automated testing for Windows, macOS, iOS, and Android
  • Chores

    • Enabled automated weekly dependency updates across the project
    • Added Homebrew as a required prerequisite for macOS installation
    • Updated default workspace and canvas directory paths

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

📝 Walkthrough

Walkthrough

This is a tremendous PR, folks—absolutely tremendous. We're talking major infrastructure overhaul here. New GitHub Actions workflows for CI across Windows, macOS, and Android platforms. We're removing old workflow files, updating path resolutions from .argentos to .argent in key places, completely restructuring the dashboard surface profile logic, and making the gateway shutdown handler way more robust. Believe me, this is big league stuff.

Changes

Cohort / File(s) Summary
GitHub Actions Workflows
.github/dependabot.yml, .github/workflows/ci.yml, .github/workflows/labeler.yml
Added three new workflow files: Dependabot configuration for automated weekly dependency updates across npm, GitHub Actions, Swift, and Gradle ecosystems; expanded CI pipeline with Windows, macOS, and Android jobs (each conditional on workflow_dispatch); and a labeler workflow that auto-applies maintainer label to PRs/issues from org members/owners using a GitHub App token.
Removed Workflow
.github/workflows/platform-manual.yml
Deleted the entire manually-triggered platform workflow that previously housed Windows/macOS/Android/iOS job definitions (471 lines)—functionality now split into new dedicated CI jobs.
Dashboard Surface Profile & Config
dashboard/api-server.cjs, dashboard/src/lib/configSurfaceProfile.ts, src/config/zod-schema.ts, src/config/config.public-core-surface.test.ts
Inverted surface profile logic: now defaults to "full" instead of "public-core", and defaults to "full" when config is missing/unparseable. Removed dashboardMode field entirely from distribution schema.
Dashboard UI Components & Widgets
dashboard/src/App.tsx, dashboard/src/components/ConfigPanelCore.tsx, dashboard/src/components/widgets/widgetRegistry.ts
Wired JobsBoardWidget and OrgChartWidget into the app and registry (replacing EmptyWidget); removed workspace tab sanitization, workforce-based gating, and dashboardMode state management; made ProjectKickoffModal always mounted; replaced SafetyRulesPanel import with inline SafetyTab; updated default dictionary config.
Removed Static Server
dashboard/static-server.cjs
Deleted 156-line standalone HTTP server that served dashboard assets, handled SPA fallback routing, proxied /api requests, and enforced caching headers—this responsibility likely moved elsewhere (156 lines).
Gateway Endpoint Store
apps/macos/Sources/Argent/GatewayEndpointStore.swift, apps/macos/Tests/ArgentIPCTests/GatewayEndpointStoreTests.swift
Refactored environment variable handling to use direct reads with trimming checks instead of optional helpers; changed password/token fallback logic to return nil when env values are empty; removed comprehensive precedence tests, keeping only basic env/launchd resolution tests.
Gateway Shutdown Handler
src/gateway/server-close.ts, src/gateway/server-close.test.ts
Made all runners (heartbeat, contemplation, executionWorker, jobOrchestrator, sis, consciousnessKernel) and cron mandatory (non-optional) in params; removed defensive stopSyncHandle helper and now calls stop() directly; deleted associated test file (75 lines).
Path Resolution Refactoring
src/agents/workspace.ts, src/canvas-host/server.ts, src/daemon/paths.ts, src/daemon/paths.test.ts, src/daemon/inspect.ts, src/daemon/service-env.ts, src/daemon/service-env.test.ts
Hardcoded ~/.argent/ as base for agent workspace (removing ARGENT_STATE_DIR dependency); updated canvas root fallback to ~/.argent/canvas; added resolveGatewayConfigPath() function; changed gateway state dir defaults; narrowed launchd label ignores to only gateway label; added computed state/config path assertions in service env tests.
Runtime & Storage
src/daemon/program-args.ts, src/daemon/program-args.test.ts, src/data/storage-factory.ts
Added .git detection to prefer repo checkout over installed CLI runtime (returning null when source checkout detected); inlined dynamic import logic in createPgAdapter with cleaner error handling; added test case verifying repo-dist preference.
Documentation
README.md
Added brief prerequisite note about Homebrew requirement on macOS for PostgreSQL/Redis/system services setup (2 lines).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • Harden core workflows and second-Mac validation docs #17: Both PRs modify GitHub Actions workflow YAMLs (.github/workflows/ci.yml, labeler.yml) and normalize path references to ~/.argentos, making the changes directly related at the workflow infrastructure level.

  • ArgentAIOS/argentos#152: Both PRs add identical .git detection logic to src/daemon/program-args.ts to prefer repo checkout over installed runtime, representing directly related code-level changes.

  • config: accept dashboardMode in distribution schema #82: Both PRs directly modify the same configuration schema files (src/config/zod-schema.ts, src/config/config.public-core-surface.test.ts) but in opposite directions—this PR removes dashboardMode while the other adds it, creating a direct conflict.

Poem

🚀 Workflows and paths, we're reshaping the game,
From .argentos to .argent—reorganizing with fame!
Dashboard widgets now shine, no more empty displays,
Gateway runners stand strong through all of their days.
Trump-approved infrastructure, believe me, it's great!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is severely incomplete, containing only 'Fix.' without addressing any required template sections like Summary, Scope, Validation, Impact, Risk, or Screenshots. Provide a comprehensive description following the template: explain what changed and why, check relevant scope boxes, document validation steps performed, describe install/runtime impact, discuss potential regressions, and include screenshots/logs if UI behavior changed.
Docstring Coverage ⚠️ Warning Docstring coverage is 3.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: onboarding blocking' clearly summarizes the main objective—fixing onboarding blocking issues—which aligns with the commit message and the extensive changes across CI/CD, paths, and macOS app files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 fix/onboarding-block-v2

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 13

Caution

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

⚠️ Outside diff range comments (2)
apps/macos/Sources/Argent/GatewayEndpointStore.swift (1)

87-126: ⚠️ Potential issue | 🟡 Minor

Make the password warning match the token path.

Right now this logs an “overrides” warning even when the config password and ARGENT_GATEWAY_PASSWORD are identical. Because the warning is one-shot, that false positive can also suppress the real mismatch warning later. Not good.

💡 Small fix
-            if let configPassword = self.resolveConfigPassword(isRemote: isRemote, root: root),
-               !configPassword.isEmpty
+            if let configPassword = self.resolveConfigPassword(isRemote: isRemote, root: root),
+               !configPassword.isEmpty,
+               configPassword != trimmed
             {
                 self.warnEnvOverrideOnce(
                     kind: .password,
                     envVar: "ARGENT_GATEWAY_PASSWORD",
                     configKey: isRemote ? "gateway.remote.password" : "gateway.auth.password")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/macos/Sources/Argent/GatewayEndpointStore.swift` around lines 87 - 126,
The warning currently logs an override anytime both an env password and a config
password exist even if they are identical; change the logic in the
ARGENT_GATEWAY_PASSWORD handling so you first obtain the config value via
resolveConfigPassword(isRemote:root:), trim it and compare it to the env-derived
trimmed value, and only call warnEnvOverrideOnce(kind:.password,
envVar:"ARGENT_GATEWAY_PASSWORD", configKey: ...) when the two trimmed values
differ; keep the existing return of the env value when present. Ensure you
reference resolveConfigPassword and warnEnvOverrideOnce and compare trimmed
strings to avoid false-positive one-shot warnings.
dashboard/src/App.tsx (1)

4922-4922: ⚠️ Potential issue | 🔴 Critical

Add the missing closing </div> tag before the next ternary condition.

The outer wrapper opened at line 4922 never closes before the next ternary arm on line 5043. This will break JSX parsing. The verification shows 12 opening <div> tags versus only 10 closing tags in this section—tremendous problem, folks!

✅ Minimal fix
           </div>
+        </div>
       ) : showWorkforce && allowWorkforceSurface ? (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dashboard/src/App.tsx` at line 4922, In App.tsx the JSX wrapper <div
className="flex-1 flex flex-col min-h-0 overflow-hidden"> is not closed, causing
mismatched tags and broken JSX; add a matching closing </div> immediately before
the start of the next ternary/conditional branch so the fragment inside the App
component (the block that opens with <div className="flex-1 flex flex-col
min-h-0 overflow-hidden">) is properly closed and all nested divs balance.
🧹 Nitpick comments (5)
dashboard/src/components/ConfigPanelCore.tsx (1)

41-46: Folks, we have a tremendous dictionary here, but the IDs? Not so great.

Look, I've seen a lot of IDs in my time — the best IDs, believe me — and this sequence goes 1, 2, 3, then jumps right to 5. Where's 4? Did somebody forget about 4? It's like building the most beautiful building and skipping the fourth floor. The code works, it's still winning, but for consistency and future maintainability, you might want to fix that numbering. Very minor, very small potatoes, but we like perfection here.

🔧 Proposed fix to make the IDs sequential — believe me, it's beautiful
   dictionary: [
     { id: "1", term: "COMEX", replacement: "Coe-Mex", enabled: true },
     { id: "2", term: "oz", replacement: "ounces", enabled: true },
     { id: "3", term: "SGE", replacement: "Shanghai Gold Exchange", enabled: true },
-    { id: "5", term: "API", replacement: "A P I", enabled: true },
+    { id: "4", term: "API", replacement: "A P I", enabled: true },
   ],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dashboard/src/components/ConfigPanelCore.tsx` around lines 41 - 46, The
dictionary array in ConfigPanelCore.tsx has non-sequential IDs (entries in the
dictionary property: { id: "1" ... }, { id: "2" ... }, { id: "3" ... }, then {
id: "5" ... }) — update the id value on the final entry in the dictionary array
from "5" to "4" so IDs are sequential; locate the dictionary constant/prop in
ConfigPanelCore (the dictionary array) and change the id string for the API
replacement entry to "4".
src/data/storage-factory.ts (1)

202-213: Add a documentation comment explaining the dynamic import pattern for optional dependencies.

The new Function pattern is a standard technique in this codebase for optional dependencies like the PostgreSQL adapter. Since it's intentionally used across multiple files (storage-factory.ts and storage-factory-core.ts), consider adding a brief comment to clarify the design choice for future developers.

📝 Suggested documentation comment
 async function createPgAdapter(config: StorageConfig): Promise<StorageAdapter> {
   if (!config.postgres) {
     throw new Error("StorageConfig: postgres config is required for PG adapter");
   }
+  // Using dynamic import via new Function to allow truly runtime resolution
+  // of optional pg-adapter module, preventing bundlers from statically analyzing
+  // dependencies that may not be present in all deployment environments.
   let PgAdapter: new (postgres: NonNullable<StorageConfig["postgres"]>) => StorageAdapter;

CSP is not a concern in this codebase — the configured policy only restricts frame ancestors, not eval operations.

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

In `@src/data/storage-factory.ts` around lines 202 - 213, Add a brief
documentation comment above the dynamic import block explaining that the new
Function("specifier","return import(specifier)") pattern is intentionally used
to load optional dependencies at runtime (here to obtain PgAdapter) without
static import/require; mention that this mirrors the pattern used in
storage-factory-core.ts, that it returns a Promise resolving to an object with
PgAdapter (a constructor matching StorageAdapter), and note CSP is not a concern
in this codebase (CSP only restricts frame-ancestors). Include references to
PgAdapter, dynamicImport, and StorageAdapter in the comment so future
maintainers can quickly find and understand the pattern and rationale.
.github/workflows/ci.yml (2)

410-411: iOS job disabled—I get it, but let's keep an eye on this!

Look, you've got if: false here which means this beautiful iOS test setup (simulators, coverage gates, the whole thing) is just sitting there doing nothing. That's fine for now—sometimes you gotta focus on what's important—but don't forget about it. Dead code gets stale, and when you flip that switch to true, things might not work like they used to.

Consider adding a TODO or tracking issue so this doesn't become forgotten infrastructure.

Would you like me to create a tracking issue to remind you to re-enable iOS CI when ready?

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

In @.github/workflows/ci.yml around lines 410 - 411, The iOS CI job is disabled
by setting the 'ios' job's conditional to "if: false"; add a short TODO comment
above the 'ios' job and create or reference a tracking issue so the disabled
state isn't forgotten—update the 'ios' job block to include a comment like
"TODO: re-enable iOS CI — see ISSUE-XXXX" and create/link that issue in your
issue tracker, or add an entry to the repo's roadmap so whoever flips 'if:
false' back to true has the context and checklist for revalidating simulators,
coverage gates, and any platform-specific setup.

22-33: Lots of repeated code here—could be tremendous with a composite action!

I'm seeing the same submodule retry logic copied 7 times across this file. Same with the pnpm setup. Now look, I understand—GitHub Actions makes you do this sometimes—but if you wanted to make this really classy, you could extract these into a composite action or reusable workflow.

Something like .github/actions/checkout-with-submodules/action.yml. It would make maintenance much easier, believe me. But hey, it works as-is, so this is just a suggestion for when you want to make it even better.

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

In @.github/workflows/ci.yml around lines 22 - 33, The "Checkout submodules
(retry)" shell step and the repeated pnpm setup blocks are duplicated across the
workflow; extract the retry logic into a reusable composite action (e.g., a new
action that runs the git submodule loop using the existing git submodule update
--init --force --depth=1 --recursive command and retry sleep strategy) and
similarly extract the pnpm setup into a reusable action or workflow call, then
replace each duplicated step with calls to those new actions so the workflow
uses the single reusable action instead of copying the shell block seven times.
apps/macos/Tests/ArgentIPCTests/GatewayEndpointStoreTests.swift (1)

13-37: Keep the config-before-launchd assertion here.

Right now this only proves env wins and launchd is the fallback. The resolver still has config sitting in the middle, and if that branch slips, local auth can quietly choose the wrong credential. Easy one to lock down.

🧪 Add the missing precedence check
         let envToken = GatewayEndpointStore._testResolveGatewayToken(
             isRemote: false,
             root: [:],
             env: ["ARGENT_GATEWAY_TOKEN": "env-token"],
             launchdSnapshot: snapshot)
         `#expect`(envToken == "env-token")
 
+        let configToken = GatewayEndpointStore._testResolveGatewayToken(
+            isRemote: false,
+            root: [
+                "gateway": [
+                    "auth": [
+                        "token": "config-token",
+                    ],
+                ],
+            ],
+            env: [:],
+            launchdSnapshot: snapshot)
+        `#expect`(configToken == "config-token")
+
         let fallbackToken = GatewayEndpointStore._testResolveGatewayToken(
             isRemote: false,
             root: [:],
             env: [:],
             launchdSnapshot: snapshot)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/macos/Tests/ArgentIPCTests/GatewayEndpointStoreTests.swift` around lines
13 - 37, The test currently only verifies env wins and launchd is fallback; add
assertions to verify config (passed via the root parameter) sits between env and
launchd in precedence. Call GatewayEndpointStore._testResolveGatewayToken with
root: ["ARGENT_GATEWAY_TOKEN": "config-token"], env: [:], launchdSnapshot:
snapshot and assert the result equals "config-token" to ensure config overrides
launchd, and also add a case with env present (env: ["ARGENT_GATEWAY_TOKEN":
"env-token"], root: ["ARGENT_GATEWAY_TOKEN": "config-token"]) asserting the
result is "env-token" to ensure env still beats config; use the existing test
function resolveGatewayTokenPrefersEnvAndFallsBackToLaunchd and the
_testResolveGatewayToken symbol to locate where to add these assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/dependabot.yml:
- Around line 1-113: Dependabot is configured to run Swift updates for
directories "/apps/shared/MoltbotKit" and "/Swabble" which do not exist; either
remove the two swift update blocks referencing those directories (the
package-ecosystem: swift entries with directory: /apps/shared/MoltbotKit and
directory: /Swabble) from .github/dependabot.yml or create the missing
directories and add valid Swift package manifests there so Dependabot can run;
ensure you keep the working swift block for directory: /apps/macos and the other
ecosystems unchanged.

In @.github/workflows/ci.yml:
- Around line 393-396: The workflow step named "Select Xcode 26.1" is selecting
a non-existent path (/Applications/Xcode_26.1.app); update that run command to
point to an available Xcode bundle (for example /Applications/Xcode_26.1.1.app)
or another supported version (26.0.1, 26.2, 26.3) so xcode-select -s uses a real
installation and xcodebuild -version succeeds.

In @.github/workflows/labeler.yml:
- Around line 3-7: The workflow currently triggers on both pull_request_target
and issues but the label job assumes context.payload.pull_request exists (used
in the early return), so scope jobs to their relevant events: update the label
job to run only when github.event_name == 'pull_request_target' (or check
context.payload.pull_request) and any issue-only job to run only when
github.event_name == 'issues'; use job-level if conditions (referencing the
label job and context.payload.pull_request) so the label job won't execute for
issue events and compute won't be wasted.

In `@dashboard/src/App.tsx`:
- Around line 1119-1125: The localStorage initializer for workspaceTabs accepts
any JSON and can return invalid shapes (null, object, legacy), causing
workspaceTabs.map to crash; update the initializer (the useState call that
defines workspaceTabs and setWorkspaceTabs) to parse "argent-workspaces", verify
the parsed value is an Array, and that each item conforms to the WorkspaceTab
shape (has required properties like id and name, optional icon),
filter/transform valid entries, and fall back to the default [{ id: "home",
name: "Home", icon: "🏠" }] if validation fails or parsing throws.
- Line 1110: The component currently seeds surfaceProfile to "full" which causes
the add-only operations tab to appear before the async profile fetch and on
transient failures; change the initial useState for surfaceProfile to a neutral
value (e.g., undefined or null) and only call setSurfaceProfile("full" |
"public-core" etc.) after the async fetch resolves successfully; update the
effect that adds the operations tab to run only when surfaceProfile is
explicitly "full" (guard on surfaceProfile !== undefined) and stop
writing/persisting the operations workspace on transient settings errors—do not
setSurfaceProfile("full") in the transient-failure paths (the code referenced by
setSurfaceProfile and the add-operations effect should be the targets).

In `@dashboard/src/lib/configSurfaceProfile.ts`:
- Around line 21-28: Do not "fail open" to "full" when the config is missing,
malformed, or contains unexpected values; instead have the parser return a
neutral/absent value so callers must explicitly opt into unlocking. Update the
logic around rawConfigText and JSON.parse so that: if rawConfigText is empty
return undefined (not "full"); on successful parse return "public-core" only
when parsed?.distribution?.surfaceProfile === "public-core" and otherwise return
undefined; and on JSON.parse errors return undefined. Reference rawConfigText
and parsed.distribution.surfaceProfile so callers can explicitly choose to treat
undefined as "full" if they want a temporary override.

In `@src/agents/workspace.ts`:
- Around line 16-18: The change hardcodes ~/.argent/... and ignores the
ARGENT_STATE_DIR override; update the workspace path resolver to honor the
ARGENT_STATE_DIR environment override when present (fall back to the existing
homedir-based default otherwise). In the function that builds the workspace path
(the code that currently returns path.join(homedir(), ".argent",
`workspace-${profile}`) or path.join(homedir(), ".argent", "workspace")), first
check for process.env.ARGENT_STATE_DIR (or the passed-in env/stateDir value if
the caller passes an env object) and join that with the workspace name/profile;
keep the new default behavior only when the env override is absent so callers
that pass env continue to get deployment-specific state roots.

In `@src/canvas-host/server.ts`:
- Line 238: The current code builds a single-item candidates array pointing only
to path.join(os.homedir(), ".argent", "canvas"), which ignores any legacy
install location and can cause upgrades to lose existing data; update the
candidates construction (the variable named candidates) to include the legacy
canvas path(s) in order of preference (e.g., add path.join(os.homedir(),
"<legacy-dir>", "canvas") or path.join(os.homedir(), ".canvas") before the new
path) so the host will detect and prefer existing content during startup; ensure
any downstream discovery logic that iterates candidates still respects the new
order.

In `@src/daemon/inspect.ts`:
- Line 129: The change narrows ignored launchd labels to only
resolveGatewayLaunchAgentLabel(), causing first-party services (e.g.,
ai.argent.node, ai.argent.dashboard-ui, ai.argent.dashboard-api) to be reported
as “extra”; update the filtering logic in the function that returns label ===
resolveGatewayLaunchAgentLabel() so it excludes the full set of first-party
launchd labels instead of just the gateway label—use a predicate or list (e.g.,
an array of known first-party labels) and check against it where scanLaunchdDir
results are processed (refer to resolveGatewayLaunchAgentLabel(),
scanLaunchdDir, and the label variable) to restore the original exclusion
behavior.

In `@src/daemon/program-args.ts`:
- Around line 119-124: The early return when a .git directory is found is
overriding an explicit install snapshot override; update the logic in the
function that inspects currentRoot (references to currentRoot and the
fs.access(".git") check) to first detect if ARGENT_INSTALL_PACKAGE_DIR
(process.env.ARGENT_INSTALL_PACKAGE_DIR or the config variable used) is set and,
if so, skip the .git early-return path so the explicit install dir wins; adjust
the try/catch block so it only returns null for a repo checkout when no
ARGENT_INSTALL_PACKAGE_DIR is provided, and add a regression test that sets
ARGENT_INSTALL_PACKAGE_DIR and ensures the code prefers the install package dir
rather than falling back to the repo build.

In `@src/gateway/server-close.ts`:
- Around line 86-92: The direct calls to params.cron.stop(),
params.heartbeatRunner.stop(), params.contemplationRunner.stop(),
params.executionWorkerRunner.stop(), params.jobOrchestratorRunner.stop(),
params.sisRunner.stop(), and params.consciousnessKernelRunner.stop() can throw
and abort shutdown; wrap each .stop() call in a defensive try-catch (or
implement a small helper safeStop(name, runner) that calls runner.stop() inside
try-catch) so that if one runner throws we log the error via the available
logger (e.g., params.logger.error or console.error) including the runner name
and error details, then continue to the next stop call to ensure full shutdown
proceeds.
- Around line 24-30: The JobOrchestratorRunner type is currently incompatible
with code that calls .stop() on it; update the type or the shutdown call so they
match: either change the JobOrchestratorRunner type definition to include a
stop(): void (or stop: () => Promise<void> if async) so it exposes the stop
method, or make the property optional and guard the call (e.g., if
(jobOrchestratorRunner?.stop) jobOrchestratorRunner.stop()), and ensure the
shutdown sequence that invokes .stop() (the server close/shutdown routine that
iterates
cron/heartbeatRunner/contemplationRunner/executionWorkerRunner/jobOrchestratorRunner/...)
reflects the chosen signature (synchronous vs async) so types and runtime
behavior align.
- Line 90: The code calls params.jobOrchestratorRunner.stop() but
JobOrchestratorRunner is currently an empty/void type and
startJobOrchestratorRunner returns void, causing a runtime/type error; fix by
making the runner API consistent: update the JobOrchestratorRunner type to
include stop(): Promise<void> (or stop(): void) like SisRunner/HeartbeatRunner
and change startJobOrchestratorRunner to return an instance implementing that
interface, or alternatively change the call site to treat the start function as
void (remove the .stop() call or guard it with if (params.jobOrchestratorRunner
&& typeof params.jobOrchestratorRunner.stop === 'function') await
params.jobOrchestratorRunner.stop();). Ensure symbol names JobOrchestratorRunner
and startJobOrchestratorRunner are updated together so the type system and
runtime match.

---

Outside diff comments:
In `@apps/macos/Sources/Argent/GatewayEndpointStore.swift`:
- Around line 87-126: The warning currently logs an override anytime both an env
password and a config password exist even if they are identical; change the
logic in the ARGENT_GATEWAY_PASSWORD handling so you first obtain the config
value via resolveConfigPassword(isRemote:root:), trim it and compare it to the
env-derived trimmed value, and only call warnEnvOverrideOnce(kind:.password,
envVar:"ARGENT_GATEWAY_PASSWORD", configKey: ...) when the two trimmed values
differ; keep the existing return of the env value when present. Ensure you
reference resolveConfigPassword and warnEnvOverrideOnce and compare trimmed
strings to avoid false-positive one-shot warnings.

In `@dashboard/src/App.tsx`:
- Line 4922: In App.tsx the JSX wrapper <div className="flex-1 flex flex-col
min-h-0 overflow-hidden"> is not closed, causing mismatched tags and broken JSX;
add a matching closing </div> immediately before the start of the next
ternary/conditional branch so the fragment inside the App component (the block
that opens with <div className="flex-1 flex flex-col min-h-0 overflow-hidden">)
is properly closed and all nested divs balance.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 410-411: The iOS CI job is disabled by setting the 'ios' job's
conditional to "if: false"; add a short TODO comment above the 'ios' job and
create or reference a tracking issue so the disabled state isn't
forgotten—update the 'ios' job block to include a comment like "TODO: re-enable
iOS CI — see ISSUE-XXXX" and create/link that issue in your issue tracker, or
add an entry to the repo's roadmap so whoever flips 'if: false' back to true has
the context and checklist for revalidating simulators, coverage gates, and any
platform-specific setup.
- Around line 22-33: The "Checkout submodules (retry)" shell step and the
repeated pnpm setup blocks are duplicated across the workflow; extract the retry
logic into a reusable composite action (e.g., a new action that runs the git
submodule loop using the existing git submodule update --init --force --depth=1
--recursive command and retry sleep strategy) and similarly extract the pnpm
setup into a reusable action or workflow call, then replace each duplicated step
with calls to those new actions so the workflow uses the single reusable action
instead of copying the shell block seven times.

In `@apps/macos/Tests/ArgentIPCTests/GatewayEndpointStoreTests.swift`:
- Around line 13-37: The test currently only verifies env wins and launchd is
fallback; add assertions to verify config (passed via the root parameter) sits
between env and launchd in precedence. Call
GatewayEndpointStore._testResolveGatewayToken with root:
["ARGENT_GATEWAY_TOKEN": "config-token"], env: [:], launchdSnapshot: snapshot
and assert the result equals "config-token" to ensure config overrides launchd,
and also add a case with env present (env: ["ARGENT_GATEWAY_TOKEN":
"env-token"], root: ["ARGENT_GATEWAY_TOKEN": "config-token"]) asserting the
result is "env-token" to ensure env still beats config; use the existing test
function resolveGatewayTokenPrefersEnvAndFallsBackToLaunchd and the
_testResolveGatewayToken symbol to locate where to add these assertions.

In `@dashboard/src/components/ConfigPanelCore.tsx`:
- Around line 41-46: The dictionary array in ConfigPanelCore.tsx has
non-sequential IDs (entries in the dictionary property: { id: "1" ... }, { id:
"2" ... }, { id: "3" ... }, then { id: "5" ... }) — update the id value on the
final entry in the dictionary array from "5" to "4" so IDs are sequential;
locate the dictionary constant/prop in ConfigPanelCore (the dictionary array)
and change the id string for the API replacement entry to "4".

In `@src/data/storage-factory.ts`:
- Around line 202-213: Add a brief documentation comment above the dynamic
import block explaining that the new Function("specifier","return
import(specifier)") pattern is intentionally used to load optional dependencies
at runtime (here to obtain PgAdapter) without static import/require; mention
that this mirrors the pattern used in storage-factory-core.ts, that it returns a
Promise resolving to an object with PgAdapter (a constructor matching
StorageAdapter), and note CSP is not a concern in this codebase (CSP only
restricts frame-ancestors). Include references to PgAdapter, dynamicImport, and
StorageAdapter in the comment so future maintainers can quickly find and
understand the pattern and rationale.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ab3d2639-8db8-45bc-947f-3eefb237f92f

📥 Commits

Reviewing files that changed from the base of the PR and between 7ec7054 and e8af880.

📒 Files selected for processing (30)
  • .github/dependabot.yml
  • .github/workflows/ci.yml
  • .github/workflows/labeler.yml
  • .github/workflows/platform-manual.yml
  • ARGENT_ARCHITECTURE.md
  • README.md
  • VISION.md
  • apps/macos/Sources/Argent/GatewayEndpointStore.swift
  • apps/macos/Tests/ArgentIPCTests/GatewayEndpointStoreTests.swift
  • dashboard/api-server.cjs
  • dashboard/src/App.tsx
  • dashboard/src/components/ConfigPanelCore.tsx
  • dashboard/src/components/widgets/widgetRegistry.ts
  • dashboard/src/lib/configSurfaceProfile.ts
  • dashboard/static-server.cjs
  • docs.acp.md
  • src/agents/workspace.ts
  • src/canvas-host/server.ts
  • src/config/config.public-core-surface.test.ts
  • src/config/zod-schema.ts
  • src/daemon/inspect.ts
  • src/daemon/paths.test.ts
  • src/daemon/paths.ts
  • src/daemon/program-args.test.ts
  • src/daemon/program-args.ts
  • src/daemon/service-env.test.ts
  • src/daemon/service-env.ts
  • src/data/storage-factory.ts
  • src/gateway/server-close.test.ts
  • src/gateway/server-close.ts
💤 Files with no reviewable changes (5)
  • src/config/config.public-core-surface.test.ts
  • src/config/zod-schema.ts
  • src/gateway/server-close.test.ts
  • .github/workflows/platform-manual.yml
  • dashboard/static-server.cjs

Comment thread .github/dependabot.yml
Comment on lines +1 to +113
# Dependabot configuration
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2

registries:
npm-npmjs:
type: npm-registry
url: https://registry.npmjs.org
replaces-base: true

updates:
# npm dependencies (root)
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
production:
dependency-type: production
update-types:
- minor
- patch
development:
dependency-type: development
update-types:
- minor
- patch
open-pull-requests-limit: 10
registries:
- npm-npmjs

# GitHub Actions
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
actions:
patterns:
- "*"
update-types:
- minor
- patch
open-pull-requests-limit: 5

# Swift Package Manager - macOS app
- package-ecosystem: swift
directory: /apps/macos
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
swift-deps:
patterns:
- "*"
update-types:
- minor
- patch
open-pull-requests-limit: 5

# Swift Package Manager - shared MoltbotKit
- package-ecosystem: swift
directory: /apps/shared/MoltbotKit
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
swift-deps:
patterns:
- "*"
update-types:
- minor
- patch
open-pull-requests-limit: 5

# Swift Package Manager - Swabble
- package-ecosystem: swift
directory: /Swabble
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
swift-deps:
patterns:
- "*"
update-types:
- minor
- patch
open-pull-requests-limit: 5

# Gradle - Android app
- package-ecosystem: gradle
directory: /apps/android
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
android-deps:
patterns:
- "*"
update-types:
- minor
- patch
open-pull-requests-limit: 5
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the directories referenced in dependabot.yml exist
for dir in "apps/macos" "apps/shared/MoltbotKit" "Swabble" "apps/android"; do
  if [ -d "$dir" ]; then
    echo "✓ Directory exists: $dir"
  else
    echo "✗ Directory NOT found: $dir"
  fi
done

Repository: ArgentAIOS/argentos-core

Length of output: 208


The Swift directories don't exist—big problem, we need to fix this right now.

Look, this Dependabot config has excellent structure—the grouping strategy is smart, the PR limits are professional, the cooldown periods are solid. Really well done on that. But we've got a major issue here, and it's a real one.

Two of your Swift package directories in the config don't actually exist in the repository:

  • /apps/shared/MoltbotKit — not found
  • /Swabble — not found

These are referenced in lines 54-74 of the dependabot.yml, but they're not in the repo. Dependabot will fail on these entries. You need to either:

  1. Remove the non-existent directories from the configuration, or
  2. Create these directories if they should exist

The apps/macos and apps/android directories check out fine—those are good. But get those Swift entries fixed immediately. This is critical.

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

In @.github/dependabot.yml around lines 1 - 113, Dependabot is configured to run
Swift updates for directories "/apps/shared/MoltbotKit" and "/Swabble" which do
not exist; either remove the two swift update blocks referencing those
directories (the package-ecosystem: swift entries with directory:
/apps/shared/MoltbotKit and directory: /Swabble) from .github/dependabot.yml or
create the missing directories and add valid Swift package manifests there so
Dependabot can run; ensure you keep the working swift block for directory:
/apps/macos and the other ecosystems unchanged.

Comment thread .github/workflows/ci.yml
Comment on lines +393 to +396
- name: Select Xcode 26.1
run: |
sudo xcode-select -s /Applications/Xcode_26.1.app
xcodebuild -version
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

What Xcode versions are available on GitHub Actions macos-latest runner March 2026?

💡 Result:

On the GitHub Actions macos-latest runner (macOS 15 arm64) in March 2026, the available Xcode versions are: 16.4 (default), 16.3, 16.0, 26.0.1, 26.1.1, 26.2, and 26.3. To switch to a specific version, use: sudo xcode-select -s "/Applications/Xcode_X.Y.app/Contents/Developer" where X.Y is the version (e.g., Xcode_16.4.app). macos-latest labels the arm64 macOS 15 runner, as macOS 26 arm64 uses explicit macos-26 labels per official documentation. Images update weekly; latest as of early March 2026 (image version 20260303.0188.2) lists these Xcodes via runner-images Readme and release notes.

Citations:


Fix Xcode version—26.1 doesn't exist on the runner, only 26.1.1 and beyond!

Look, this is a huge problem. You're trying to select /Applications/Xcode_26.1.app on macos-latest, but here's the thing—26.1 is NOT available on GitHub Actions right now. The actual versions available are 26.0.1, 26.1.1, 26.2, and 26.3. Your job is going to fail immediately when it tries to select a non-existent app directory. You need to change this to Xcode_26.1.1.app or use one of the other available versions. Believe me, this is not working as-is.

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

In @.github/workflows/ci.yml around lines 393 - 396, The workflow step named
"Select Xcode 26.1" is selecting a non-existent path
(/Applications/Xcode_26.1.app); update that run command to point to an available
Xcode bundle (for example /Applications/Xcode_26.1.1.app) or another supported
version (26.0.1, 26.2, 26.3) so xcode-select -s uses a real installation and
xcodebuild -version succeeds.

Comment on lines +3 to +7
on:
pull_request_target:
types: [opened, synchronize, reopened]
issues:
types: [opened]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

We've got a little trigger issue here, folks—needs attention!

Look, I'm a big fan of automation, the biggest, but we have a situation. Your workflow triggers on BOTH pull_request_target AND issues events (lines 4-7), but the label job runs on all events and tries to access context.payload.pull_request which will be undefined for issue events.

The early return on line 34-36 saves you from a crash, but both jobs will run on both event types, wasting compute. That's not how we make workflows great again!

🔧 Proposed fix to scope jobs to their respective events
 jobs:
   label:
+    if: github.event_name == 'pull_request_target'
     permissions:
       contents: read
       pull-requests: write
   label-issues:
+    if: github.event_name == 'issues'
     permissions:
       issues: write
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/labeler.yml around lines 3 - 7, The workflow currently
triggers on both pull_request_target and issues but the label job assumes
context.payload.pull_request exists (used in the early return), so scope jobs to
their relevant events: update the label job to run only when github.event_name
== 'pull_request_target' (or check context.payload.pull_request) and any
issue-only job to run only when github.event_name == 'issues'; use job-level if
conditions (referencing the label job and context.payload.pull_request) so the
label job won't execute for issue events and compute won't be wasted.

Comment thread dashboard/src/App.tsx
const [avatarState, setAvatarState] = useState<AvatarState>("idle");
const [avatarMood, setAvatarMood] = useState<MoodName | undefined>(undefined);
const [surfaceProfile, setSurfaceProfile] = useState<DashboardSurfaceProfile>("public-core");
const [surfaceProfile, setSurfaceProfile] = useState<DashboardSurfaceProfile>("full");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Starting on "full" will seed a stale Operations workspace.

Big UX problem. The add-only operations-tab effect runs before the async profile fetch, so Line 1110 makes the tab appear on first mount even for installs that should resolve to public-core. Then Lines 1301-1303 do the same thing on transient settings failures. Since nothing removes that tab afterward, it gets persisted to argent-workspaces and users can keep landing on a workspace they are not allowed to use.

Also applies to: 1301-1303

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

In `@dashboard/src/App.tsx` at line 1110, The component currently seeds
surfaceProfile to "full" which causes the add-only operations tab to appear
before the async profile fetch and on transient failures; change the initial
useState for surfaceProfile to a neutral value (e.g., undefined or null) and
only call setSurfaceProfile("full" | "public-core" etc.) after the async fetch
resolves successfully; update the effect that adds the operations tab to run
only when surfaceProfile is explicitly "full" (guard on surfaceProfile !==
undefined) and stop writing/persisting the operations workspace on transient
settings errors—do not setSurfaceProfile("full") in the transient-failure paths
(the code referenced by setSurfaceProfile and the add-operations effect should
be the targets).

Comment thread dashboard/src/App.tsx
Comment on lines 1119 to 1125
const [workspaceTabs, setWorkspaceTabs] = useState<WorkspaceTab[]>(() => {
try {
const stored = localStorage.getItem("argent-workspaces");
if (stored) {
const parsed = JSON.parse(stored) as WorkspaceTab[];
return sanitizeWorkspaceTabs(parsed, false);
}
if (stored) return JSON.parse(stored);
} catch {}
return DEFAULT_WORKSPACE_TABS;
return [{ id: "home", name: "Home", icon: "🏠" }];
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate argent-workspaces before you trust it.

Right now any JSON value is accepted. If storage contains null, an object, or a legacy shape, the first render reaches workspaceTabs.map(...) and the dashboard falls over. We need the old sanitize/fallback step back here.

🛠️ A tighter initializer
   const [workspaceTabs, setWorkspaceTabs] = useState<WorkspaceTab[]>(() => {
     try {
       const stored = localStorage.getItem("argent-workspaces");
-      if (stored) return JSON.parse(stored);
+      if (stored) {
+        const parsed = JSON.parse(stored);
+        if (Array.isArray(parsed)) {
+          const tabs = parsed.filter(
+            (tab): tab is WorkspaceTab =>
+              tab &&
+              typeof tab === "object" &&
+              typeof tab.id === "string" &&
+              typeof tab.name === "string" &&
+              typeof tab.icon === "string",
+          );
+          if (tabs.length > 0) return tabs;
+        }
+      }
     } catch {}
     return [{ id: "home", name: "Home", icon: "🏠" }];
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dashboard/src/App.tsx` around lines 1119 - 1125, The localStorage initializer
for workspaceTabs accepts any JSON and can return invalid shapes (null, object,
legacy), causing workspaceTabs.map to crash; update the initializer (the
useState call that defines workspaceTabs and setWorkspaceTabs) to parse
"argent-workspaces", verify the parsed value is an Array, and that each item
conforms to the WorkspaceTab shape (has required properties like id and name,
optional icon), filter/transform valid entries, and fall back to the default [{
id: "home", name: "Home", icon: "🏠" }] if validation fails or parsing throws.

Comment thread src/daemon/inspect.ts
return (
label === resolveGatewayLaunchAgentLabel() || IGNORED_FIRST_PARTY_LAUNCHD_LABELS.has(label)
);
return label === resolveGatewayLaunchAgentLabel();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Restore first-party launchd label filtering here — this change causes false positives.

At Line 129, narrowing ignore logic to only the gateway label means first-party services like ai.argent.node, ai.argent.dashboard-ui, and ai.argent.dashboard-api now flow into scanLaunchdDir results as “extra” services. That’s a big regression risk for onboarding/service cleanup UX.

Suggested fix
-import {
-  GATEWAY_SERVICE_KIND,
-  GATEWAY_SERVICE_MARKER,
-  resolveGatewayLaunchAgentLabel,
-  resolveGatewaySystemdServiceName,
-  resolveGatewayWindowsTaskName,
-} from "./constants.js";
+import {
+  GATEWAY_SERVICE_KIND,
+  GATEWAY_SERVICE_MARKER,
+  resolveDashboardApiLaunchAgentLabel,
+  resolveDashboardUiLaunchAgentLabel,
+  resolveGatewayLaunchAgentLabel,
+  resolveGatewaySystemdServiceName,
+  resolveGatewayWindowsTaskName,
+  resolveNodeLaunchAgentLabel,
+} from "./constants.js";
+const IGNORED_FIRST_PARTY_LAUNCHD_LABELS = new Set<string>([
+  resolveGatewayLaunchAgentLabel(),
+  resolveNodeLaunchAgentLabel(),
+  resolveDashboardUiLaunchAgentLabel(),
+  resolveDashboardApiLaunchAgentLabel(),
+]);
+
 function isIgnoredLaunchdLabel(label: string): boolean {
-  return label === resolveGatewayLaunchAgentLabel();
+  return IGNORED_FIRST_PARTY_LAUNCHD_LABELS.has(label);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/daemon/inspect.ts` at line 129, The change narrows ignored launchd labels
to only resolveGatewayLaunchAgentLabel(), causing first-party services (e.g.,
ai.argent.node, ai.argent.dashboard-ui, ai.argent.dashboard-api) to be reported
as “extra”; update the filtering logic in the function that returns label ===
resolveGatewayLaunchAgentLabel() so it excludes the full set of first-party
launchd labels instead of just the gateway label—use a predicate or list (e.g.,
an array of known first-party labels) and check against it where scanLaunchdDir
results are processed (refer to resolveGatewayLaunchAgentLabel(),
scanLaunchdDir, and the label variable) to restore the original exclusion
behavior.

Comment on lines +119 to +124
try {
await fs.access(path.join(currentRoot, ".git"));
return null;
} catch {
// Not a source checkout; keep considering installed runtime snapshots.
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't let .git override the explicit install package dir.

Big regression. If ARGENT_INSTALL_PACKAGE_DIR is set, this early return null still fires inside a real checkout, so the service falls back to the repo build instead of the requested runtime snapshot. Keep the .git shortcut for the default ~/.argentos/... probe, but let the explicit override win. I’d also add the matching regression test.

💡 Suggested fix
 async function resolveInstalledCliEntrypointPathForService(): Promise<string | null> {
   const stateDir =
     process.env.ARGENT_STATE_DIR ||
     (process.env.HOME ? path.join(process.env.HOME, ".argentos") : undefined);
+  const hasExplicitInstallPackageDir = Boolean(
+    process.env.ARGENT_INSTALL_PACKAGE_DIR?.trim(),
+  );
   const installPackageDir =
     process.env.ARGENT_INSTALL_PACKAGE_DIR ||
     (stateDir ? path.join(stateDir, "lib", "node_modules", "argentos") : undefined);
@@
   if (currentArgv1) {
     const currentRoot = resolveProjectRootFromEntrypoint(currentArgv1);
     const installedRoot = resolveProjectRootFromEntrypoint(resolvedInstalledCliPath);
-    try {
-      await fs.access(path.join(currentRoot, ".git"));
-      return null;
-    } catch {
-      // Not a source checkout; keep considering installed runtime snapshots.
-    }
+    if (!hasExplicitInstallPackageDir) {
+      try {
+        await fs.access(path.join(currentRoot, ".git"));
+        return null;
+      } catch {
+        // Not a source checkout; keep considering installed runtime snapshots.
+      }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
await fs.access(path.join(currentRoot, ".git"));
return null;
} catch {
// Not a source checkout; keep considering installed runtime snapshots.
}
async function resolveInstalledCliEntrypointPathForService(): Promise<string | null> {
const stateDir =
process.env.ARGENT_STATE_DIR ||
(process.env.HOME ? path.join(process.env.HOME, ".argentos") : undefined);
const hasExplicitInstallPackageDir = Boolean(
process.env.ARGENT_INSTALL_PACKAGE_DIR?.trim(),
);
const installPackageDir =
process.env.ARGENT_INSTALL_PACKAGE_DIR ||
(stateDir ? path.join(stateDir, "lib", "node_modules", "argentos") : undefined);
if (currentArgv1) {
const currentRoot = resolveProjectRootFromEntrypoint(currentArgv1);
const installedRoot = resolveProjectRootFromEntrypoint(resolvedInstalledCliPath);
if (!hasExplicitInstallPackageDir) {
try {
await fs.access(path.join(currentRoot, ".git"));
return null;
} catch {
// Not a source checkout; keep considering installed runtime snapshots.
}
}
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/daemon/program-args.ts` around lines 119 - 124, The early return when a
.git directory is found is overriding an explicit install snapshot override;
update the logic in the function that inspects currentRoot (references to
currentRoot and the fs.access(".git") check) to first detect if
ARGENT_INSTALL_PACKAGE_DIR (process.env.ARGENT_INSTALL_PACKAGE_DIR or the config
variable used) is set and, if so, skip the .git early-return path so the
explicit install dir wins; adjust the try/catch block so it only returns null
for a repo checkout when no ARGENT_INSTALL_PACKAGE_DIR is provided, and add a
regression test that sets ARGENT_INSTALL_PACKAGE_DIR and ensures the code
prefers the install package dir rather than falling back to the repo build.

Comment on lines +24 to +30
cron: { stop: () => void };
heartbeatRunner: HeartbeatRunner;
contemplationRunner: ContemplationRunner;
executionWorkerRunner: ExecutionWorkerRunner;
jobOrchestratorRunner: JobOrchestratorRunner;
sisRunner: SisRunner;
consciousnessKernelRunner: ConsciousnessKernelRunner;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify JobOrchestratorRunner type definition
echo "=== JobOrchestratorRunner type definition ==="
rg -n "export type JobOrchestratorRunner" -A 5

echo ""
echo "=== Check if stop method exists anywhere in job-orchestrator files ==="
ast-grep --pattern 'stop() {
  $$$
}'

Repository: ArgentAIOS/argentos-core

Length of output: 283


Fix this JobOrchestratorRunner disaster—massive type mismatch!

We've got a huge problem here, folks. JobOrchestratorRunner is defined as Record<string, never> (total empty type), but line 90 is calling .stop() on it. That's going to blow up at runtime—total nightmare! Either add the stop() method to the type definition or get rid of this runner requirement. This is a big one. We need to fix it now—not later, now.

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

In `@src/gateway/server-close.ts` around lines 24 - 30, The JobOrchestratorRunner
type is currently incompatible with code that calls .stop() on it; update the
type or the shutdown call so they match: either change the JobOrchestratorRunner
type definition to include a stop(): void (or stop: () => Promise<void> if
async) so it exposes the stop method, or make the property optional and guard
the call (e.g., if (jobOrchestratorRunner?.stop) jobOrchestratorRunner.stop()),
and ensure the shutdown sequence that invokes .stop() (the server close/shutdown
routine that iterates
cron/heartbeatRunner/contemplationRunner/executionWorkerRunner/jobOrchestratorRunner/...)
reflects the chosen signature (synchronous vs async) so types and runtime
behavior align.

Comment on lines +86 to +92
params.cron.stop();
params.heartbeatRunner.stop();
params.contemplationRunner.stop();
params.executionWorkerRunner.stop();
params.jobOrchestratorRunner.stop();
params.sisRunner.stop();
params.consciousnessKernelRunner.stop();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

We removed the safety nets—not good, not good at all!

The previous implementation had defensive shutdown handling that was absolutely tremendous—it caught errors and kept going. Now we're just calling .stop() directly without any try-catch protection. If any of these runners throws an exception—and believe me, things can go wrong—the entire shutdown sequence stops dead in its tracks. Redis stays open, storage adapters don't close, WebSocket connections hang around. It's a mess, a complete mess.

This is especially concerning because:

  1. The AI summary confirms tests covering "missing runner handles" were deleted
  2. These are synchronous calls that could throw synchronous exceptions

We need error handling here, folks. Make shutdown great again!

🛡️ Proposed fix to add defensive error handling
-    params.cron.stop();
-    params.heartbeatRunner.stop();
-    params.contemplationRunner.stop();
-    params.executionWorkerRunner.stop();
-    params.jobOrchestratorRunner.stop();
-    params.sisRunner.stop();
-    params.consciousnessKernelRunner.stop();
+    try { params.cron.stop(); } catch { /* ignore */ }
+    try { params.heartbeatRunner.stop(); } catch { /* ignore */ }
+    try { params.contemplationRunner.stop(); } catch { /* ignore */ }
+    try { params.executionWorkerRunner.stop(); } catch { /* ignore */ }
+    try { params.jobOrchestratorRunner.stop(); } catch { /* ignore */ }
+    try { params.sisRunner.stop(); } catch { /* ignore */ }
+    try { params.consciousnessKernelRunner.stop(); } catch { /* ignore */ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
params.cron.stop();
params.heartbeatRunner.stop();
params.contemplationRunner.stop();
params.executionWorkerRunner.stop();
params.jobOrchestratorRunner.stop();
params.sisRunner.stop();
params.consciousnessKernelRunner.stop();
try { params.cron.stop(); } catch { /* ignore */ }
try { params.heartbeatRunner.stop(); } catch { /* ignore */ }
try { params.contemplationRunner.stop(); } catch { /* ignore */ }
try { params.executionWorkerRunner.stop(); } catch { /* ignore */ }
try { params.jobOrchestratorRunner.stop(); } catch { /* ignore */ }
try { params.sisRunner.stop(); } catch { /* ignore */ }
try { params.consciousnessKernelRunner.stop(); } catch { /* ignore */ }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/gateway/server-close.ts` around lines 86 - 92, The direct calls to
params.cron.stop(), params.heartbeatRunner.stop(),
params.contemplationRunner.stop(), params.executionWorkerRunner.stop(),
params.jobOrchestratorRunner.stop(), params.sisRunner.stop(), and
params.consciousnessKernelRunner.stop() can throw and abort shutdown; wrap each
.stop() call in a defensive try-catch (or implement a small helper
safeStop(name, runner) that calls runner.stop() inside try-catch) so that if one
runner throws we log the error via the available logger (e.g.,
params.logger.error or console.error) including the runner name and error
details, then continue to the next stop call to ensure full shutdown proceeds.

params.heartbeatRunner.stop();
params.contemplationRunner.stop();
params.executionWorkerRunner.stop();
params.jobOrchestratorRunner.stop();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check all runner type definitions for consistency
echo "=== All Runner type exports ==="
rg -n "export type.*Runner\s*=" src/infra/ -A 3

echo ""
echo "=== Check if JobOrchestratorRunner has any actual implementation ==="
rg -n "JobOrchestratorRunner" --type ts

Repository: ArgentAIOS/argentos-core

Length of output: 3828


🏁 Script executed:

# Check the actual implementation of startJobOrchestratorRunner
echo "=== startJobOrchestratorRunner implementation ==="
cat -n src/infra/job-orchestrator-runner.ts | head -20

echo ""
echo "=== How jobOrchestratorRunner is assigned in server.impl.ts ==="
sed -n '725,735p' src/gateway/server.impl.ts

echo ""
echo "=== Check server-close.ts context around line 90 ==="
sed -n '85,95p' src/gateway/server-close.ts

echo ""
echo "=== Check if TypeScript compilation catches this ==="
rg "jobOrchestratorRunner" src/gateway/server-close.ts -B 2 -A 2

Repository: ArgentAIOS/argentos-core

Length of output: 1827


🏁 Script executed:

# Check if there are type assertions or casts hiding this
echo "=== Check for type assertions around jobOrchestratorRunner assignment ==="
sed -n '725,735p' src/gateway/server.impl.ts

echo ""
echo "=== Check type context in server-close.ts for the parameter ==="
sed -n '20,35p' src/gateway/server-close.ts

echo ""
echo "=== Search for any 'as' casts or type assertions related to jobOrchestratorRunner ==="
rg "jobOrchestratorRunner.*as\s" src/

echo ""
echo "=== Check the full function signature of server-close ==="
sed -n '1,30p' src/gateway/server-close.ts

Repository: ArgentAIOS/argentos-core

Length of output: 3292


🏁 Script executed:

# Check tsconfig and TypeScript settings
echo "=== Check tsconfig.json ==="
cat tsconfig.json | head -50

echo ""
echo "=== Look for any `@ts-ignore` or `@ts-expect-error` around line 730 in server.impl.ts ==="
sed -n '725,735p' src/gateway/server.impl.ts

echo ""
echo "=== Look for suppressions in server-close.ts around line 90 ==="
sed -n '88,92p' src/gateway/server-close.ts

echo ""
echo "=== Check if there's actually a void being assigned (very literal check) ==="
rg "startJobOrchestratorRunner" src/gateway/server.impl.ts -A 1 -B 1

Repository: ArgentAIOS/argentos-core

Length of output: 2002


The JobOrchestratorRunner type is completely broken, and that .stop() call will fail.

Here's the deal: startJobOrchestratorRunner returns void, but you're assigning it to a variable typed as JobOrchestratorRunner — which is Record<string, never> (an empty object). Then you try to call .stop() on it. That's a major winner of a TypeError, believe me.

The function is marked as a stub ("No-op in Core"), but the type system is a disaster. You need to either:

  1. Make JobOrchestratorRunner actually include the stop() method (like SisRunner, HeartbeatRunner, etc. — they're all doing it the right way), or
  2. Handle the void return properly instead of pretending it's a real runner

With TypeScript's strict mode on, this should already be screaming at you with compilation errors. Fix this type — it's a critical mess.

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

In `@src/gateway/server-close.ts` at line 90, The code calls
params.jobOrchestratorRunner.stop() but JobOrchestratorRunner is currently an
empty/void type and startJobOrchestratorRunner returns void, causing a
runtime/type error; fix by making the runner API consistent: update the
JobOrchestratorRunner type to include stop(): Promise<void> (or stop(): void)
like SisRunner/HeartbeatRunner and change startJobOrchestratorRunner to return
an instance implementing that interface, or alternatively change the call site
to treat the start function as void (remove the .stop() call or guard it with if
(params.jobOrchestratorRunner && typeof params.jobOrchestratorRunner.stop ===
'function') await params.jobOrchestratorRunner.stop();). Ensure symbol names
JobOrchestratorRunner and startJobOrchestratorRunner are updated together so the
type system and runtime match.

@webdevtodayjason
Copy link
Copy Markdown
Contributor Author

Triaging this as an internal-core refactor proposal rather than a narrowly scoped bugfix. The diff overlaps several launch-day fixes that have already landed in smaller PRs, so this should be refreshed/rebased and narrowed before merge; otherwise it is likely superseded by the targeted fixes already on main.

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