Skip to content

feat(slack): add message reactions to track conversation status#1475

Open
KiranChilledOut wants to merge 6 commits intocoleam00:devfrom
KiranChilledOut:feature/slack-reactions
Open

feat(slack): add message reactions to track conversation status#1475
KiranChilledOut wants to merge 6 commits intocoleam00:devfrom
KiranChilledOut:feature/slack-reactions

Conversation

@KiranChilledOut
Copy link
Copy Markdown

@KiranChilledOut KiranChilledOut commented Apr 28, 2026

Summary

Describe this PR in 2-5 bullets:

  • Problem: Users had no visual feedback on Slack about conversation state while AI was processing
  • Why it matters: Users couldn't tell if their message was acknowledged, being worked on, or completed
  • What changed: Added emoji reactions to Slack messages to track conversation status: 👀 (acknowledged), 🔄 (work begins), ✅ (success), ❌ (failure)
  • What did not change: Other platforms (Telegram, GitHub, Discord) remain unaffected - reaction methods are optional in interface

UX Journey

Before

User                   Archon                   AI Client
───                   ──────                   ─────────
sends message ──────▶  resolves session
                       loads context
                       streams to AI ──────────▶ processes prompt
                       receives chunks ◀──────── streams response
sees reply ◀─────────  sends to platform
(no status visible)

After

User                   Archon                   AI Client
───                   ──────                   ─────────
sends message ──────▶  adds 👀 reaction
                       loads context
                       streams to AI ──────────▶ processes prompt
                       adds 🔄 reaction
                       receives chunks ◀──────── streams response
                       removes 👀🔄
sees reply + ✅ ──────  adds ✅ reaction

Architecture Diagram

Before

(Map ALL modules touched or connected to this change.)

┌─────────────┐     ┌─────────────┐
│ Slack       │────▶│ Orchestrator│
│ Adapter     │     └─────────────┘
└─────────────┘            │
                          ▼
                   ┌─────────────┐
                   │ IPlatform   │
                   │ Adapter     │
                   └─────────────┘

After

(Same diagram with changes highlighted. Mark new modules with [+], removed with [-],
 modified with [~]. Mark new connections with ===, removed with --x--.)

┌─────────────┐     ┌─────────────┐
│ Slack       │────▶│ Orchestrator│
│ Adapter     │     └─────────────┘
└─────────────┘            │
     ▲                      ▼
     │              ┌─────────────┐
     │              │ IPlatform   │
     │              │ Adapter     │
     │              └─────────────┘
     │                    [+ addReaction/removeReaction]
     └────────────────────[async, non-blocking]

Connection inventory (list every module-to-module edge, mark changes):

From To Status Notes
Orchestrator SlackAdapter modified Added reaction calls with error handling
Orchestrator IPlatformAdapter modified Added optional addReaction/removeReaction methods
Orchestrator TelegramAdapter unchanged Methods not called for non-Slack platforms
Orchestrator GitHubAdapter unchanged Methods not called for non-Slack platforms

Label Snapshot

  • Risk: risk: low
  • Size: size: S
  • Scope: adapters:slack
  • Module: adapters:slack

Change Metadata

  • Change type: feature
  • Primary scope: adapters

Linked Issue

  • Closes # (add issue number if applicable)
  • Related #
  • Depends on # (if stacked)
  • Supersedes # (if replacing older PR)

Validation Evidence (required)

Commands and result summary:

bun run type-check
bun run lint
bun run format:check
bun run test
# Or all at once:
bun run validate
  • Evidence provided (test/log/trace/screenshot): Test file added (packages/adapters/src/chat/slack/adapter.test.ts) covers reaction functions, all tests pass
  • If any command is intentionally skipped, explain why: None

Security Impact (required)

  • New permissions/capabilities? (No)
  • New external network calls? (No - uses existing Slack SDK, no new endpoints)
  • Secrets/tokens handling changed? (No)
  • File system access scope changed? (No)
  • If any Yes, describe risk and mitigation: N/A

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Database migration needed? (No)
  • If yes, exact upgrade steps: N/A

Human Verification (required)

What was personally validated beyond CI:

  • Verified scenarios: Tested reaction flows locally with mock Slack client
  • Edge cases checked: Error handling with try/finally ensures cleanup on failures (commit 79da658)
  • What was not verified: Production Slack deployment with real messages

Side Effects / Blast Radius (required)

  • Affected subsystems/workflows: Slack adapter only; other platforms unaffected
  • Potential unintended effects: None - reactions are non-blocking with try/finally
  • Guardrails/monitoring for early detection: Error handling in place, failures logged

Rollback Plan (required)

  • Fast rollback command/path: git revert cee0fd01 79da658c
  • Feature flags or config toggles (if any): None
  • Observable failure symptoms: Missing reactions on Slack messages

Risks and Mitigations

List real risks in this PR (or write None).

  • Risk: Slack API rate limits

    • Mitigation: Reactions are non-blocking with try/finally, failures logged but don't halt conversation flow
  • Risk: Reaction methods not implemented on other platforms

    • Mitigation: Methods are optional in IPlatformAdapter interface, implementation checks before calling

Summary by CodeRabbit

  • New Features

    • Slack reaction feedback: emoji lifecycle (received/working/succeeded/failed) with add/remove support.
    • New script node type and maintainer-standup workflow/CLI for synthesized briefs.
    • Automatic PR base verification and retargeting after PR creation.
  • Bug Fixes

    • Orchestrator clears stale assistant sessions on execution errors to avoid reuse.
  • Documentation

    • Updated developer binary resolution, Pi backends, and script-node usage docs.

Add emoji reactions to Slack messages to give users visual feedback on
conversation state:
- 👀 (eyes) when message is acknowledged
- 🔄 (arrows_counterclockwise) when work begins
- Clean up intermediate reactions before final status
- ✅ (white_check_mark) on success
- ❌ (x) on failure

The addReaction/removeReaction methods are optional in IPlatformAdapter
to maintain backwards compatibility with other platforms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

Adds platform reaction APIs and Slack adapter reaction methods; integrates reaction lifecycle into the orchestrator with safe wrappers; extends adapter types; enables clearing persisted assistant session IDs; plus broad workflow/tooling updates, tests, docs, and multiple package/version bumps.

Changes

Cohort / File(s) Summary
Adapter types
packages/core/src/types/index.ts
Adds optional addReaction / removeReaction to IPlatformAdapter.
Slack adapter & tests
packages/adapters/src/chat/slack/adapter.ts, packages/adapters/src/chat/slack/adapter.test.ts
Implements addReaction/removeReaction parsing channel:timestamp, with validation, logging, and unit tests for valid and malformed conversation IDs.
Orchestrator & safe helpers
packages/core/src/orchestrator/orchestrator-agent.ts, packages/core/src/orchestrator/orchestrator-agent.test.ts, packages/core/src/orchestrator/safe-reaction.test.ts
Integrates reaction lifecycle into handleMessage, adds exported safeAddReaction/safeRemoveReaction wrappers that swallow adapter failures, and updates tests to verify reaction flow and session-clearing on execution errors.
Session DB & tests
packages/core/src/db/sessions.ts, packages/core/src/db/sessions.test.ts
updateSession signature now accepts `sessionId: string
Workflows — loader & executor
packages/workflows/src/loader.ts, packages/workflows/src/loader.test.ts, packages/workflows/src/dag-executor.ts, packages/workflows/src/dag-executor.test.ts
Switches provider validation to require registered provider ids; adds mutates_checkout and tags parsing; strips code fences when scanning output refs; treats empty AI output as node failure (with events); loop support for $LOOP_PREV_OUTPUT; approval on_reject id fix; extensive executor test additions.
Executor shared & tests
packages/workflows/src/executor-shared.ts, packages/workflows/src/executor-shared.test.ts
Adds formatSubprocessFailure (sanitizes/truncates diagnostics) and loopPrevOutput support in variable substitution; tests expanded.
Script nodes & docs
packages/docs-web/src/content/docs/guides/script-nodes.md, .archon/workflows/...
New script-node docs and many workflow defaults updated (model pins, verify-pr-base node insertion).
Claude binary resolver & tests
packages/providers/src/claude/binary-resolver.ts, packages/providers/src/claude/binary-resolver-dev.test.ts
Resolver now honors CLAUDE_BIN_PATH and autodetects native install under $HOME/.local/bin/claude; tests updated for env-priority behaviors.
Pi structured output
packages/providers/src/community/pi/event-bridge.ts, packages/providers/src/community/pi/event-bridge.test.ts
tryParseStructuredOutput recovers JSON when preceded by prose preamble; tests extended for varied patterns.
Maintainer standup tooling
.archon/scripts/maintainer-standup-persist.ts, .archon/commands/*, .archon/workflows/maintainer/*, .archon/workflows/defaults/*
Adds persist script to extract embedded state and save briefs/state; new maintainer-standup workflows and verify-pr-base nodes across defaults.
CI, packaging, misc
package.json (root), packages/*/package.json, CHANGELOG.md, .github/workflows/e2e-smoke.yml, docker-entrypoint.sh, .gitignore
Version bumps to 0.3.10 across packages, dependency pins (Anthropic SDK), changelog updates, GH Actions env export change, Docker git safe.directory handling, and gitignore additions for generated artifacts.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Orchestrator
    participant SlackAdapter
    participant SlackAPI as Slack API

    User->>Orchestrator: posts message (channel:timestamp)
    Orchestrator->>SlackAdapter: safeAddReaction("channel:ts","eyes")
    SlackAdapter->>SlackAPI: reactions.add(channel, timestamp, reaction)
    SlackAPI-->>SlackAdapter: success / error
    SlackAdapter-->>Orchestrator: resolved

    Orchestrator->>Orchestrator: start AI work
    Orchestrator->>SlackAdapter: safeAddReaction("channel:ts","arrows_counterclockwise")
    SlackAdapter->>SlackAPI: reactions.add
    SlackAPI-->>SlackAdapter: success

    Note over Orchestrator: on success or failure
    Orchestrator->>SlackAdapter: safeRemoveReaction("channel:ts","arrows_counterclockwise")
    SlackAdapter->>SlackAPI: reactions.remove
    SlackAPI-->>SlackAdapter: success
    Orchestrator->>SlackAdapter: safeAddReaction("channel:ts","white_check_mark" or "x")
    SlackAdapter->>SlackAPI: reactions.add
    SlackAPI-->>SlackAdapter: success
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • leex279

Poem

🐇 I hopped through code with twitchy nose,
I nudged reactions where the message goes,
Eyes then arrows, cleared with a cheer,
A check or an X to finish near.
Hooray for logs, tests, and one small prose! 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary feature: adding Slack emoji reactions to track conversation status during message handling.
Description check ✅ Passed The description follows the template structure with all required sections: Summary (with 4 bullets), UX Journey (Before/After), Architecture Diagram, Change Metadata, Linked Issue, Validation Evidence, Security Impact, Compatibility/Migration, Human Verification, Side Effects, Rollback Plan, and Risks/Mitigations.
Docstring Coverage ✅ Passed Docstring coverage is 91.30% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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

🧹 Nitpick comments (1)
packages/adapters/src/chat/slack/adapter.ts (1)

210-250: Use guideline-compliant log event names for reaction lifecycle events.

The new event keys (slack.reaction_added, slack.reaction_failed, etc.) don’t follow the required {domain}.{action}_{state} convention with standard states.

♻️ Suggested log key adjustments
-      getLog().warn({ conversationId, reaction }, 'slack.reaction_invalid_conversation_id');
+      getLog().warn({ conversationId, reaction }, 'slack.reaction_add_rejected');
...
-      getLog().debug({ channelId, timestamp, reaction }, 'slack.reaction_added');
+      getLog().debug({ channelId, timestamp, reaction }, 'slack.reaction_add_completed');
...
-      getLog().warn({ err, channelId, timestamp, reaction }, 'slack.reaction_failed');
+      getLog().warn({ err, channelId, timestamp, reaction }, 'slack.reaction_add_failed');
...
-      getLog().warn({ conversationId, reaction }, 'slack.remove_reaction_invalid_conversation_id');
+      getLog().warn({ conversationId, reaction }, 'slack.reaction_remove_rejected');
...
-      getLog().debug({ channelId, timestamp, reaction }, 'slack.reaction_removed');
+      getLog().debug({ channelId, timestamp, reaction }, 'slack.reaction_remove_completed');
...
-      getLog().warn({ err, channelId, timestamp, reaction }, 'slack.remove_reaction_failed');
+      getLog().warn({ err, channelId, timestamp, reaction }, 'slack.reaction_remove_failed');

As per coding guidelines "Structured logging with Pino: use event naming format {domain}.{action}_{state} (standard states: _started, _completed, _failed, _validated, _rejected)".

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

In `@packages/adapters/src/chat/slack/adapter.ts` around lines 210 - 250, The log
event names for the reaction lifecycle don't follow the
{domain}.{action}_{state} convention; update all getLog() calls in addReaction
and removeReaction to use standardized keys: replace
slack.reaction_invalid_conversation_id -> slack.reaction_add_rejected,
slack.reaction_added -> slack.reaction_add_completed, slack.reaction_failed ->
slack.reaction_add_failed; and for removal replace
slack.remove_reaction_invalid_conversation_id -> slack.reaction_remove_rejected,
slack.reaction_removed -> slack.reaction_remove_completed,
slack.remove_reaction_failed -> slack.reaction_remove_failed; keep the same
metadata objects and places (inside async addReaction and removeReaction, and
the catch blocks) so only the event key strings change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/orchestrator/orchestrator-agent.ts`:
- Around line 547-549: The call to platform.addReaction? (e.g., await
platform.addReaction?.(conversationId, 'eyes')) should not be awaited directly
because adapter errors can bubble up and break core message handling; make
reaction updates fire-and-forget and ensure they run (or are attempted) in a
finally block so intermediate reactions aren't left behind—wrap calls to
platform.addReaction? and any other optional reaction hooks used in the file in
try/catch that logs errors but does not throw, or invoke them without await
(e.g., start a Promise and ignore its rejection) and move these invocations into
a finally section of the surrounding handler (references: platform.addReaction?,
conversationId, any reaction hook calls around the message handling functions)
so reactions are resilient and non-blocking.

---

Nitpick comments:
In `@packages/adapters/src/chat/slack/adapter.ts`:
- Around line 210-250: The log event names for the reaction lifecycle don't
follow the {domain}.{action}_{state} convention; update all getLog() calls in
addReaction and removeReaction to use standardized keys: replace
slack.reaction_invalid_conversation_id -> slack.reaction_add_rejected,
slack.reaction_added -> slack.reaction_add_completed, slack.reaction_failed ->
slack.reaction_add_failed; and for removal replace
slack.remove_reaction_invalid_conversation_id -> slack.reaction_remove_rejected,
slack.reaction_removed -> slack.reaction_remove_completed,
slack.remove_reaction_failed -> slack.reaction_remove_failed; keep the same
metadata objects and places (inside async addReaction and removeReaction, and
the catch blocks) so only the event key strings change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 83541177-42a1-4dad-a558-33ec2a4a9882

📥 Commits

Reviewing files that changed from the base of the PR and between 7d06773 and cee0fd0.

📒 Files selected for processing (6)
  • packages/adapters/src/chat/slack/adapter.test.ts
  • packages/adapters/src/chat/slack/adapter.ts
  • packages/cli/src/commands/setup.test.ts
  • packages/cli/src/commands/setup.ts
  • packages/core/src/orchestrator/orchestrator-agent.ts
  • packages/core/src/types/index.ts

Comment thread packages/core/src/orchestrator/orchestrator-agent.ts
@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented Apr 29, 2026

Review Summary

Verdict: minor-fixes-needed

Your PR adds Slack emoji reaction feedback (👀 on message receive, 🔄 during AI work, ✅/❌ on completion) — a nice UX enhancement that's correctly isolated from core message processing. The adapter implementation and error handling are solid. Two items need attention before merge:

Blocking issues

None.

Suggested fixes

  • Add tests for the orchestrator reaction helperspackages/core/src/orchestrator/orchestrator-agent.ts:72-98, 580, 872, 944-982

    Your safeAddReaction/safeRemoveReaction helpers are the core of this feature but have no tests. The existing orchestrator-agent.test.ts mock doesn't include addReaction/removeReaction, so the optional chaining silently no-ops without assertion. Create a dedicated test file (e.g., safe-reaction.test.ts) to avoid mock pollution with the existing complex mock setup. Test:

    1. Helper calls platform.addReaction when it exists
    2. Helper gracefully returns when platform.addReaction is undefined (interface optional)
    3. Helper catches and logs errors without throwing
    4. The eyes reaction appears on message receipt (line 580)
    5. The arrows_counterclockwise reaction appears when AI work starts (line 872)
    6. Success path removes intermediates and adds ✅ (lines 944-953)
    7. Error path removes intermediates and adds ❌ (lines 972-982)
  • Document the reaction feature in Slack adapter docspackages/docs-web/src/content/docs/adapters/slack.md

    Two things are missing:

    1. A "Reaction Feedback" section describing the emoji workflow (👀 → 🔄 → ✅/❌)
    2. reactions:write added to the bot token scopes list (required for the feature)

Minor / nice-to-have

  • Trim verbose JSDoc @param descriptionsadapter.ts:202, 208, 222, 252: @param conversationId - Format: "channel:timestamp"@param conversationId - Slack: "channel:timestamp" (or just @param conversationId). The "Format:" prefix is noise.

  • Remove redundant finally-block commentsorchestrator-agent.ts:956, 977, 987: The comment // No additional cleanup needed adds no value; the finally block is self-explanatory.

  • Align log event namingorchestrator-agent.ts:87, 104: reaction_add_failedorchestrator.reaction_add_failed (or similar) to match project convention.

  • Add CHANGELOG entry — Add: "Orchestrator now shows emoji reaction feedback on Slack messages (👀 → 🔄 → ✅/❌) during workflow execution." under [Unreleased].

Compliments

  • The adapter layer (adapter.test.ts) has thorough coverage for addReaction and removeReaction — good to see.
  • Error handling is exemplary: reactions fail silently with structured logs, never breaking core message flow. The safeReaction pattern is clean.
  • The JSDoc on safeAddReaction/safeRemoveReaction captures the non-obvious design decision (reactions must not block messages) clearly.

Reviewed via maintainer-review-pr workflow (Pi/Minimax). Aspects run: code-review, error-handling, test-coverage, comment-quality, docs-impact.

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

♻️ Duplicate comments (1)
packages/core/src/orchestrator/orchestrator-agent.ts (1)

949-974: ⚠️ Potential issue | 🟠 Major

Move reaction teardown/final status into a real finally.

This block is still inside the main try, so any early success return above it skips cleanup entirely. In this function that includes the approval/command paths at Line 631, Line 722, Line 747, Line 754, Line 761, and Line 778, which means eyes/arrows_counterclockwise can still be left on the message even though the comment says otherwise.

♻️ Minimal structure that preserves cleanup on every exit path
 export async function handleMessage(
   platform: IPlatformAdapter,
   conversationId: string,
   message: string,
   context?: HandleMessageContext
 ): Promise<void> {
+  let finalReaction: 'white_check_mark' | 'x' | null = 'white_check_mark';
   const { issueContext, threadContext, parentConversationId, isolationHints, attachedFiles } =
     context ?? {};
   try {
     getLog().debug({ conversationId }, 'orchestrator_message_received');
     await safeAddReaction(platform, conversationId, 'eyes');
@@
     getLog().debug({ conversationId }, 'orchestrator_message_completed');
-
-    // Reaction cleanup and final status (ensures even on early returns)
-    try {
-      await safeRemoveReaction(platform, conversationId, 'eyes');
-      await safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise');
-      await safeAddReaction(platform, conversationId, 'white_check_mark');
-    } finally {
-      // No additional cleanup needed
-    }
   } catch (error) {
+    finalReaction = 'x';
     const err = toError(error);
     getLog().error({ err, conversationId }, 'orchestrator_message_failed');
-
-    // Reaction cleanup and final status (ensures even on exceptions)
-    try {
-      await safeRemoveReaction(platform, conversationId, 'eyes');
-      await safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise');
-      await safeAddReaction(platform, conversationId, 'x');
-    } finally {
-      // No additional cleanup needed
-    }
-
     const userMessage = classifyAndFormatError(err);
     try {
       await platform.sendMessage(conversationId, userMessage);
     } catch (sendError) {
       getLog().error({ err: toError(sendError), conversationId }, 'error_notification_failed');
     }
+  } finally {
+    await safeRemoveReaction(platform, conversationId, 'eyes');
+    await safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise');
+    if (finalReaction) {
+      await safeAddReaction(platform, conversationId, finalReaction);
+    }
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/orchestrator/orchestrator-agent.ts` around lines 949 - 974,
The reaction teardown currently lives inside the main try block and is skipped
by early returns; move the cleanup/final-status logic into a real finally that
always runs after the main try/catch. Specifically, remove the
safeRemoveReaction(platform, conversationId, 'eyes') /
safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise') and the
safeAddReaction(platform, conversationId, 'white_check_mark'|'x') calls from
inside the try/catch bodies and place them in a single finally block after the
catch so that safeRemoveReaction and safeAddReaction are always invoked (use the
existing safeRemoveReaction and safeAddReaction calls and
conversationId/platform variables). Ensure the catch still logs the error with
getLog().error({ err, conversationId }, 'orchestrator_message_failed') before
the finally runs.
🧹 Nitpick comments (4)
docker-entrypoint.sh (1)

22-31: Constrain safe.directory discovery and make additions idempotent.

This loop appends on every container start, so safe.directory duplicates accumulate in ~/.gitconfig. Also, scanning all of /.archon is broader than necessary; Git repositories only reside under /.archon/workspaces/ and /.archon/worktrees/, while other paths contain non-repo artifacts.

Proposed patch
-find /.archon -name ".git" -prune -print 2>/dev/null | while IFS= read -r git_dir; do
-  $RUNNER git config --global --add safe.directory "$(dirname "$git_dir")"
-done
+find /.archon/workspaces /.archon/worktrees -name ".git" -prune -print 2>/dev/null | while IFS= read -r git_dir; do
+  repo_dir="$(dirname "$git_dir")"
+  if ! $RUNNER git config --global --get-all safe.directory 2>/dev/null | grep -Fqx -- "$repo_dir"; then
+    $RUNNER git config --global --add safe.directory "$repo_dir"
+  fi
+done
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-entrypoint.sh` around lines 22 - 31, Limit discovery to only
/.archon/workspaces and /.archon/worktrees and make additions idempotent: change
the find invocation to search those two directories (instead of /.archon) and,
inside the loop that uses $RUNNER and git_dir, check whether the directory is
already registered (use git config --global --get-all safe.directory and test
with a fixed-string match) before calling $RUNNER git config --global --add
safe.directory "$(dirname "$git_dir")"; this prevents duplicate entries in
~/.gitconfig while only targeting actual repo locations.
.archon/workflows/defaults/archon-feature-development.yaml (1)

19-29: Make verify-pr-base best-effort to avoid false workflow failures.

With set -euo pipefail, transient gh failures (or missing BASE_BRANCH) can fail the whole workflow after PR creation. Consider degrading this node to warn-and-continue.

Resiliency-focused diff
   - id: verify-pr-base
     bash: |
-      set -euo pipefail
-      EXPECTED="$BASE_BRANCH"
-      ACTUAL=$(gh pr view --json baseRefName -q '.baseRefName')
+      set -uo pipefail
+      EXPECTED="${BASE_BRANCH:-}"
+      if [ -z "$EXPECTED" ]; then
+        echo "Skipping PR base verification: BASE_BRANCH is not set" >&2
+        exit 0
+      fi
+      ACTUAL=$(gh pr view --json baseRefName -q '.baseRefName' 2>/dev/null || true)
+      if [ -z "$ACTUAL" ]; then
+        echo "Skipping PR base verification: unable to read PR base" >&2
+        exit 0
+      fi
       if [ "$ACTUAL" != "$EXPECTED" ]; then
-        PR_NUMBER=$(gh pr view --json number -q '.number')
+        PR_NUMBER=$(gh pr view --json number -q '.number' 2>/dev/null || true)
+        if [ -z "$PR_NUMBER" ]; then
+          echo "Could not resolve PR number; skipping re-target" >&2
+          exit 0
+        fi
         echo "Base mismatch on PR #$PR_NUMBER: expected=$EXPECTED actual=$ACTUAL — re-targeting" >&2
-        gh pr edit "$PR_NUMBER" --base "$EXPECTED"
+        gh pr edit "$PR_NUMBER" --base "$EXPECTED" || echo "Retarget failed; continuing" >&2
       else
         echo "PR base verified: $EXPECTED"
       fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.archon/workflows/defaults/archon-feature-development.yaml around lines 19 -
29, The current bash step using set -euo pipefail can cause the workflow to fail
on transient gh failures or missing BASE_BRANCH; change the script to be
best-effort by guarding gh calls and empty variables: check if EXPECTED is
non-empty before proceeding, capture ACTUAL with a tolerant command like
ACTUAL=$(gh pr view --json baseRefName -q '.baseRefName' 2>/dev/null || true),
treat missing ACTUAL as a warning (echo to stderr) and skip re-targeting, and
make PR_NUMBER and gh pr edit calls similarly tolerant (e.g., PR_NUMBER=$(gh pr
view --json number -q '.number' 2>/dev/null || true) and only run gh pr edit if
both PR_NUMBER and EXPECTED/ACTUAL are present), so the step warns on errors
instead of failing the workflow.
packages/workflows/src/loader.ts (1)

408-425: Normalize case before deduping tags, or relax the comment.

The comment says values like GitLab / GitLab / gitlab should not survive as distinct tags, but this implementation only trims and dedupes exact strings. Right now GitLab and gitlab still come back as two tags.

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

In `@packages/workflows/src/loader.ts` around lines 408 - 425, The code trims and
dedupes raw.tags but doesn't normalize case, so values like "GitLab" and
"gitlab" remain distinct; update the tag normalization in the block that sets
tags (the raw.tags -> tags transformation) to normalize case before deduping
(e.g., .map(t => t.trim().toLowerCase()) before passing to new Set) so
case-insensitive duplicates are removed, then, if you need to preserve original
casing choose a deterministic canonicalization step after dedupe; keep the
invalid-block warning via getLog().warn({ filename, value: raw.tags },
'invalid_tags_block_ignored') unchanged.
packages/workflows/src/dag-executor.test.ts (1)

6177-6229: Relax the Bun syntax error location assertion to prevent brittle test failures.

The expect(errorMsg).toContain('[eval]') check depends on Bun's current error format, which is not guaranteed across versions. Bun's syntax error reporting uses formats like "at loadAndEvaluateModule (2:1)" rather than explicitly including [eval] in stderr location tokens—this can vary without any change to Archon's sanitizer. Keep the "no command body leak + bounded diagnostics" assertions (prefix strip, length cap) and either remove the location check or replace it with a more stable marker like checking for "SyntaxError" or an actual line/column number.

This aligns with the principle: "Prefer reproducible commands and locked dependency behavior in CI-sensitive paths; keep tests deterministic — no flaky timing or network dependence without guardrails."

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

In `@packages/workflows/src/dag-executor.test.ts` around lines 6177 - 6229, The
brittle assertion in the test "failure message strips the \"Command failed: bun
-e <body>\" prefix and stays small" checks for "[eval]" in errorMsg; replace
that check with a more stable assertion (e.g., assert errorMsg contains
"SyntaxError" or a line/column pattern like /\d+:\d+/) or remove the location
assertion entirely so the test only verifies prefix stripping and length bounds.
Locate the failing assertion on errorMsg (the
expect(errorMsg).toContain('[eval]') line) and update it to something like
expect(errorMsg).toMatch(/SyntaxError|\d+:\d+/) or simply delete that expect to
avoid Bun-version-dependent failures. Ensure the other assertions (no "Command
failed:" prefix, no leaked script body, length < 2100) remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.archon/scripts/maintainer-standup-persist.ts:
- Around line 96-102: The filename is currently derived from new
Date().toLocaleDateString('sv-SE') which can drift; instead extract the standup
date from the generated content and use that when building briefPath/statePath.
Locate the code that constructs date/briefPath/statePath (variables date,
briefPath, statePath) and replace the wall-clock-derived date with the parsed
standup date (e.g., parse the "Maintainer Standup — YYYY-MM-DD" heading or use
the date field from the parsed payload) and format it as 'YYYY-MM-DD' before
resolving briefsDir/briefPath; ensure state.json uses the same derived date
consistently.
- Around line 38-105: Validate parsed outputs and abort before any writes: after
parsing into state/brief (the branches that set state, brief, and source from
the delimiter or JSON-wrapper fallback) add strict checks that reject malformed
data and call process.exit(1) without writing. Specifically, for the delimiter
branch verify raw contains nothing after ARCHON_STATE_JSON_END (ensure endIdx
=== raw.indexOf(END, beginIdx)), confirm the extracted state is an object
(typeof === 'object' && state !== null && !Array.isArray(state)) and that
required state keys exist with correct types; for the JSON-wrapper branch ensure
parsed.next_state is a non-array object and parsed.brief_markdown is a non-empty
string and that brief contains the heading '# Maintainer Standup' (or fail if
missing). Only proceed to mkdirSync/writeFileSync when all validations pass;
otherwise emit descriptive stderr messages and exit without touching files.

In @.archon/workflows/defaults/archon-architect.yaml:
- Around line 315-316: Replace the ad-hoc "--body \"...\"" usage in the gh pr
create step with logic that loads the repository PR template and supplies that
as the PR body (ensuring every section is filled); specifically update the step
that runs `gh pr create --base $BASE_BRANCH --title "..." --body "..."` to read
the repository's PULL_REQUEST_TEMPLATE.md into the body, programmatically
populate any placeholders, and pass that content to `gh pr create` so the repo
template is always used.

In @.archon/workflows/defaults/archon-piv-loop.yaml:
- Around line 700-704: The pipeline currently masks git push failures by using
"git push -u origin HEAD 2>&1 || echo ..." in the "Step 1: Push Changes" step,
which allows the workflow to continue to the PR creation that uses "gh pr create
--draft --base $BASE_BRANCH"; change this so a failed push stops the job: remove
the "|| echo ..." masking and instead fail the step when git push returns
non‑zero (for example, run git push and if it fails echo a clear error and exit
1, or enable errexit for the step) so the pipeline does not attempt PR creation
if the branch was not pushed.
- Around line 398-403: The TASK_COUNT assignment currently appends the fallback
"0" via "|| echo '0'", producing two lines when grep exits non-zero; change it
to capture grep -c output only and then apply parameter expansion to default to
zero if empty — e.g., assign TASK_COUNT to the result of grep -c (suppressing
errors to /dev/null) and then set TASK_COUNT=${TASK_COUNT:-0} before the numeric
comparison; update the code referencing TASK_COUNT and keep PLAN_FILE and the
grep command intact.

In @.archon/workflows/defaults/archon-ralph-dag.yaml:
- Around line 651-663: The verify-pr-base step should early-exit when no PR was
created: add a preliminary check using gh pr view --json number (or similar) to
detect if a PR exists and if it returns empty or non-existent, echo a "no PR to
verify, skipping" message and exit 0; otherwise proceed with the existing ACTUAL
vs EXPECTED base verification and retarget logic. Update the verify-pr-base job
(referenced by id: verify-pr-base and its use of ACTUAL/EXPECTED and gh pr view)
to perform this existence check before fetching baseRefName so the workflow
doesn't fail when the run ended without creating a PR.

In @.archon/workflows/defaults/archon-refactor-safely.yaml:
- Around line 449-451: The gh PR creation step currently constructs its own
body; update the `gh pr create --base $BASE_BRANCH --title "..." --body "..."`
invocation so it explicitly copies the repository PR template into the PR body
(e.g., read the repo's PR template file and pass it to gh via --body-file or
substitute the file contents into --body) to ensure every required section from
the official template is present when creating PRs.

In `@CHANGELOG.md`:
- Around line 46-56: The file contains a second set of "### Added", "###
Changed", and "### Fixed" headings for the same 0.3.10 entry which violates Keep
a Changelog/MD024; merge the duplicate blocks into the initial "### Added", "###
Changed", and "### Fixed" sections (or convert the duplicate headings into plain
bullets/subheadings under the same version) so each heading appears only once
per version; ensure the detailed bullets about $LOOP_PREV_OUTPUT, provider/model
resolution (referencing the text that mentions
inferProviderFromModel/isModelCompatible and the provider resolution chain
node.provider ?? workflow.provider ?? config.assistant), and the bash/script
node fix (referencing formatSubprocessFailure and dag.node_empty_output) are
preserved under their respective single headings.

In `@package.json`:
- Line 3: Revert the manual version bump in package.json: undo the change that
sets the root "version" key to "0.3.10" so this branch does not modify the
package.json version; leave the version at whatever value was in dev/main before
this PR (i.e., remove the "0.3.10" edit) and let the release workflow own the
version bump and changelog generation. Ensure only non-release changes remain in
this commit and do not add any other release-related edits.

In `@packages/core/src/orchestrator/orchestrator-agent.ts`:
- Around line 72-104: Add orchestrator-level tests that exercise safeAddReaction
and safeRemoveReaction and the lifecycle in handleMessage: create a fake
IPlatformAdapter instance with (a) no addReaction/removeReaction to assert
no-ops, (b) addReaction/removeReaction that throw to assert errors are swallowed
and getLog().warn is called, and (c) a normal adapter to assert handleMessage
triggers the reaction sequence (eyes → spinner → success/fail) in order; use
spies/mocks on platform methods and on getLog().warn to verify calls and
ordering.

In `@packages/docs-web/src/content/docs/getting-started/ai-assistants.md`:
- Line 63: Reword the sentence about claudeBinaryPath to clarify its scope:
replace the phrase "config-file `claudeBinaryPath` is intentionally
binary-mode-only (per-repo, not per-machine)" with text that explains
claudeBinaryPath can be set either repo-locally in .archon/config.yaml
(repo-scoped) or globally in ~/.archon/config.yaml (machine-scoped), and note
that CLAUDE_BIN_PATH environment variable still overrides both; update
references to `claudeBinaryPath`, `CLAUDE_BIN_PATH`, and the two config files to
make the repo vs machine distinction explicit.

In `@packages/providers/src/community/pi/event-bridge.ts`:
- Around line 186-196: The fallback recovery currently finds only the first "{"
(variable firstBrace) in cleaned and thus misses array-root JSON; update the
logic in event-bridge.ts around cleaned, firstBrace, and JSON.parse so it scans
for the earliest occurrence of either "{" or "[" (e.g., compute indices for both
characters, ignore -1s, pick the smallest positive index) and then
JSON.parse(cleaned.slice(firstOpenIndex)) when that index > 0; keep the same
try/catch behavior so structuredOutput recovery works for top-level arrays as
well as objects.

In `@packages/workflows/src/dag-executor.test.ts`:
- Around line 6858-6895: The test "trigger_rule: none_failed skips dependent
node + anyFailed still marks run failed" doesn't assert that node 'c' was
skipped; update the test that calls executeDagWorkflow to explicitly assert skip
behavior by checking mockStore.nodeSkipped was called for node id 'c' (or, if
nodeSkipped helper isn't available, assert mockStore.nodeCompleted/nodeExecuted
was NOT called with 'c'). Locate the test block using the nodes array and
executeDagWorkflow invocation and add a final expectation that verifies
mockStore.nodeSkipped (or absence of node_completed/ node execution call) for
'c' so the test actually proves 'c' was skipped.

In `@packages/workflows/src/loader.test.ts`:
- Around line 31-34: The calls to clearRegistry() and registerBuiltinProviders()
run at module import and mutate global provider state; move this bootstrap into
test setup/teardown so registry is deterministic: remove the top-level
clearRegistry()/registerBuiltinProviders() and instead call clearRegistry()
before each test (or in a beforeEach/beforeAll hook) and call
registerBuiltinProviders() inside that setup, then restore/clear the registry in
an afterEach/afterAll hook; reference the clearRegistry and
registerBuiltinProviders symbols and ensure any tests that rely on a
pre-populated registry explicitly invoke the setup helper so state is not shared
across test files.

In `@packages/workflows/src/loader.ts`:
- Around line 155-165: The current stripMarkdownCode function removes both
fenced code blocks and inline backtick segments, which prevents load-time
validation (substituteNodeOutputRefs) from catching placeholders inside inline
code; change stripMarkdownCode to only strip fenced code blocks (```...```) and
leave inline `...` segments intact, then keep using stripMarkdownCode when
collecting sources for node.prompt and (for loops) node.loop.prompt so inline
placeholders remain present for substituteNodeOutputRefs and load-time checks;
reference stripMarkdownCode, substituteNodeOutputRefs, node.prompt,
node.loop.prompt, and isLoopNode when making this change.

---

Duplicate comments:
In `@packages/core/src/orchestrator/orchestrator-agent.ts`:
- Around line 949-974: The reaction teardown currently lives inside the main try
block and is skipped by early returns; move the cleanup/final-status logic into
a real finally that always runs after the main try/catch. Specifically, remove
the safeRemoveReaction(platform, conversationId, 'eyes') /
safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise') and the
safeAddReaction(platform, conversationId, 'white_check_mark'|'x') calls from
inside the try/catch bodies and place them in a single finally block after the
catch so that safeRemoveReaction and safeAddReaction are always invoked (use the
existing safeRemoveReaction and safeAddReaction calls and
conversationId/platform variables). Ensure the catch still logs the error with
getLog().error({ err, conversationId }, 'orchestrator_message_failed') before
the finally runs.

---

Nitpick comments:
In @.archon/workflows/defaults/archon-feature-development.yaml:
- Around line 19-29: The current bash step using set -euo pipefail can cause the
workflow to fail on transient gh failures or missing BASE_BRANCH; change the
script to be best-effort by guarding gh calls and empty variables: check if
EXPECTED is non-empty before proceeding, capture ACTUAL with a tolerant command
like ACTUAL=$(gh pr view --json baseRefName -q '.baseRefName' 2>/dev/null ||
true), treat missing ACTUAL as a warning (echo to stderr) and skip re-targeting,
and make PR_NUMBER and gh pr edit calls similarly tolerant (e.g., PR_NUMBER=$(gh
pr view --json number -q '.number' 2>/dev/null || true) and only run gh pr edit
if both PR_NUMBER and EXPECTED/ACTUAL are present), so the step warns on errors
instead of failing the workflow.

In `@docker-entrypoint.sh`:
- Around line 22-31: Limit discovery to only /.archon/workspaces and
/.archon/worktrees and make additions idempotent: change the find invocation to
search those two directories (instead of /.archon) and, inside the loop that
uses $RUNNER and git_dir, check whether the directory is already registered (use
git config --global --get-all safe.directory and test with a fixed-string match)
before calling $RUNNER git config --global --add safe.directory "$(dirname
"$git_dir")"; this prevents duplicate entries in ~/.gitconfig while only
targeting actual repo locations.

In `@packages/workflows/src/dag-executor.test.ts`:
- Around line 6177-6229: The brittle assertion in the test "failure message
strips the \"Command failed: bun -e <body>\" prefix and stays small" checks for
"[eval]" in errorMsg; replace that check with a more stable assertion (e.g.,
assert errorMsg contains "SyntaxError" or a line/column pattern like /\d+:\d+/)
or remove the location assertion entirely so the test only verifies prefix
stripping and length bounds. Locate the failing assertion on errorMsg (the
expect(errorMsg).toContain('[eval]') line) and update it to something like
expect(errorMsg).toMatch(/SyntaxError|\d+:\d+/) or simply delete that expect to
avoid Bun-version-dependent failures. Ensure the other assertions (no "Command
failed:" prefix, no leaked script body, length < 2100) remain unchanged.

In `@packages/workflows/src/loader.ts`:
- Around line 408-425: The code trims and dedupes raw.tags but doesn't normalize
case, so values like "GitLab" and "gitlab" remain distinct; update the tag
normalization in the block that sets tags (the raw.tags -> tags transformation)
to normalize case before deduping (e.g., .map(t => t.trim().toLowerCase())
before passing to new Set) so case-insensitive duplicates are removed, then, if
you need to preserve original casing choose a deterministic canonicalization
step after dedupe; keep the invalid-block warning via getLog().warn({ filename,
value: raw.tags }, 'invalid_tags_block_ignored') unchanged.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: cce52ffc-ce1b-4e11-af09-802e6eca8d3a

📥 Commits

Reviewing files that changed from the base of the PR and between 79da658 and bad3ca0.

⛔ Files ignored due to path filters (2)
  • bun.lock is excluded by !**/*.lock
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (48)
  • .archon/commands/defaults/archon-implement-issue.md
  • .archon/commands/maintainer-standup.md
  • .archon/scripts/maintainer-standup-persist.ts
  • .archon/workflows/defaults/archon-architect.yaml
  • .archon/workflows/defaults/archon-feature-development.yaml
  • .archon/workflows/defaults/archon-fix-github-issue.yaml
  • .archon/workflows/defaults/archon-idea-to-pr.yaml
  • .archon/workflows/defaults/archon-issue-review-full.yaml
  • .archon/workflows/defaults/archon-piv-loop.yaml
  • .archon/workflows/defaults/archon-plan-to-pr.yaml
  • .archon/workflows/defaults/archon-ralph-dag.yaml
  • .archon/workflows/defaults/archon-refactor-safely.yaml
  • .archon/workflows/defaults/archon-workflow-builder.yaml
  • .archon/workflows/maintainer/maintainer-standup-minimax.yaml
  • .archon/workflows/maintainer/maintainer-standup.yaml
  • .github/workflows/e2e-smoke.yml
  • .gitignore
  • CHANGELOG.md
  • docker-entrypoint.sh
  • package.json
  • packages/adapters/package.json
  • packages/cli/package.json
  • packages/core/package.json
  • packages/core/src/db/sessions.test.ts
  • packages/core/src/db/sessions.ts
  • packages/core/src/orchestrator/orchestrator-agent.test.ts
  • packages/core/src/orchestrator/orchestrator-agent.ts
  • packages/docs-web/package.json
  • packages/docs-web/src/content/docs/getting-started/ai-assistants.md
  • packages/docs-web/src/content/docs/guides/script-nodes.md
  • packages/git/package.json
  • packages/isolation/package.json
  • packages/paths/package.json
  • packages/providers/package.json
  • packages/providers/src/claude/binary-resolver-dev.test.ts
  • packages/providers/src/claude/binary-resolver.ts
  • packages/providers/src/community/pi/event-bridge.test.ts
  • packages/providers/src/community/pi/event-bridge.ts
  • packages/server/package.json
  • packages/web/package.json
  • packages/workflows/package.json
  • packages/workflows/src/dag-executor.test.ts
  • packages/workflows/src/dag-executor.ts
  • packages/workflows/src/defaults/bundled-defaults.generated.ts
  • packages/workflows/src/executor-shared.test.ts
  • packages/workflows/src/executor-shared.ts
  • packages/workflows/src/loader.test.ts
  • packages/workflows/src/loader.ts
✅ Files skipped from review due to trivial changes (14)
  • packages/docs-web/package.json
  • packages/workflows/package.json
  • packages/adapters/package.json
  • packages/web/package.json
  • packages/paths/package.json
  • packages/core/package.json
  • .archon/commands/defaults/archon-implement-issue.md
  • packages/isolation/package.json
  • .gitignore
  • packages/server/package.json
  • packages/docs-web/src/content/docs/guides/script-nodes.md
  • packages/providers/package.json
  • packages/cli/package.json
  • packages/git/package.json

Comment thread .archon/scripts/maintainer-standup-persist.ts
Comment thread .archon/scripts/maintainer-standup-persist.ts
Comment thread .archon/workflows/defaults/archon-architect.yaml
Comment thread .archon/workflows/defaults/archon-piv-loop.yaml
Comment thread .archon/workflows/defaults/archon-piv-loop.yaml
Comment thread packages/docs-web/src/content/docs/getting-started/ai-assistants.md
Comment thread packages/providers/src/community/pi/event-bridge.ts
Comment thread packages/workflows/src/dag-executor.test.ts
Comment thread packages/workflows/src/loader.test.ts
Comment thread packages/workflows/src/loader.ts
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.

🧹 Nitpick comments (2)
packages/core/src/orchestrator/orchestrator-agent.ts (2)

948-959: Redundant try/catch — the safe* helpers already swallow errors.

safeAddReaction and safeRemoveReaction are designed to never throw (they catch internally and log at warn). The outer try/catch block will never catch anything and adds unnecessary nesting.

♻️ Suggested simplification
     getLog().debug({ conversationId }, 'orchestrator_message_completed');

-    // Reaction cleanup and final status (ensures even on early returns)
-    try {
-      // Remove intermediate reactions before adding final status
-      await safeRemoveReaction(platform, conversationId, 'eyes');
-      await safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise');
-
-      // React with ✅ on success
-      await safeAddReaction(platform, conversationId, 'white_check_mark');
-    } catch {
-      // Silently ignore reaction errors
-    }
+    // Remove intermediate reactions before adding final status
+    await safeRemoveReaction(platform, conversationId, 'eyes');
+    await safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise');
+    // React with ✅ on success
+    await safeAddReaction(platform, conversationId, 'white_check_mark');
   } catch (error) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/orchestrator/orchestrator-agent.ts` around lines 948 - 959,
The outer try/catch around the reaction cleanup is redundant because
safeAddReaction and safeRemoveReaction already swallow and log errors; remove
the try/catch block and directly await the calls to safeRemoveReaction(platform,
conversationId, 'eyes'), safeRemoveReaction(platform, conversationId,
'arrows_counterclockwise'), and safeAddReaction(platform, conversationId,
'white_check_mark') so the code is simpler and not nested in an unused catch.

963-974: Same redundant try/catch pattern in error path.

The same simplification applies here — the outer try/catch around the safe* helpers is unnecessary.

♻️ Suggested simplification
-    // Reaction cleanup and final status (ensures even on exceptions)
-    try {
-      // Remove intermediate reactions before adding final status
-      await safeRemoveReaction(platform, conversationId, 'eyes');
-      await safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise');
-
-      // React with ❌ on failure
-      await safeAddReaction(platform, conversationId, 'x');
-    } catch {
-      // Silently ignore reaction errors
-    }
+    // Remove intermediate reactions before adding final status
+    await safeRemoveReaction(platform, conversationId, 'eyes');
+    await safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise');
+    // React with ❌ on failure
+    await safeAddReaction(platform, conversationId, 'x');

     const userMessage = classifyAndFormatError(err);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/orchestrator/orchestrator-agent.ts` around lines 963 - 974,
The outer try/catch around the final reaction cleanup is redundant because the
safe* helpers already handle their own errors; remove the surrounding try { ...
} catch { } block and simply call safeRemoveReaction(platform, conversationId,
'eyes'), safeRemoveReaction(platform, conversationId,
'arrows_counterclockwise'), and safeAddReaction(platform, conversationId, 'x')
directly so errors are managed by the safe* helpers (refer to safeRemoveReaction
and safeAddReaction and the conversationId/platform variables in the same
scope).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core/src/orchestrator/orchestrator-agent.ts`:
- Around line 948-959: The outer try/catch around the reaction cleanup is
redundant because safeAddReaction and safeRemoveReaction already swallow and log
errors; remove the try/catch block and directly await the calls to
safeRemoveReaction(platform, conversationId, 'eyes'),
safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise'), and
safeAddReaction(platform, conversationId, 'white_check_mark') so the code is
simpler and not nested in an unused catch.
- Around line 963-974: The outer try/catch around the final reaction cleanup is
redundant because the safe* helpers already handle their own errors; remove the
surrounding try { ... } catch { } block and simply call
safeRemoveReaction(platform, conversationId, 'eyes'),
safeRemoveReaction(platform, conversationId, 'arrows_counterclockwise'), and
safeAddReaction(platform, conversationId, 'x') directly so errors are managed by
the safe* helpers (refer to safeRemoveReaction and safeAddReaction and the
conversationId/platform variables in the same scope).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 95b3bcd0-e23e-412b-a433-daf036f35ca9

📥 Commits

Reviewing files that changed from the base of the PR and between bad3ca0 and 1f5397c.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • packages/adapters/src/chat/slack/adapter.ts
  • packages/core/package.json
  • packages/core/src/orchestrator/orchestrator-agent.ts
  • packages/core/src/orchestrator/safe-reaction.test.ts
  • packages/docs-web/src/content/docs/adapters/slack.md
✅ Files skipped from review due to trivial changes (1)
  • packages/docs-web/src/content/docs/adapters/slack.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/package.json
  • packages/adapters/src/chat/slack/adapter.ts

@KiranChilledOut
Copy link
Copy Markdown
Author

@Wirasm thank you for the feedback and review . I've added your suggestion. (Archon to the moon 🚀🚀🚀

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.

2 participants