Skip to content

fix: wrapper layer gaps — sync/async convergence, kanban FD leak, exception handling#1908

Merged
MervinPraison merged 2 commits into
mainfrom
claude/issue-1863-20260607-0813
Jun 13, 2026
Merged

fix: wrapper layer gaps — sync/async convergence, kanban FD leak, exception handling#1908
MervinPraison merged 2 commits into
mainfrom
claude/issue-1863-20260607-0813

Conversation

@MervinPraison

@MervinPraison MervinPraison commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Fixes #1863

Addresses wrapper-layer gaps: shared run preparation for sync/async paths, kanban dispatcher file-handle leak, and narrower exception handling.

Generated with Claude Code; PR opened from triage branch claude/issue-1863-20260607-0813.

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Config loading now supports workflow-style YAML and respects CLI overrides, routing workflow configs to the appropriate workflow runner.
  • Bug Fixes

    • Improved error logging and handling during task dispatch and worker shutdown, with clearer context for failures and safer subprocess teardown.
  • Refactor

    • Centralized configuration and run preparation for sync/async flows to remove duplicate logic and provide consistent behavior.

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b1ecceb3-27ed-4f2a-917a-920d0a138a8f

📥 Commits

Reviewing files that changed from the base of the PR and between 05ce83e and a90d96d.

📒 Files selected for processing (2)
  • src/praisonai/praisonai/agents_generator.py
  • src/praisonai/praisonai/gateway/kanban_dispatcher.py
💤 Files with no reviewable changes (2)
  • src/praisonai/praisonai/agents_generator.py
  • src/praisonai/praisonai/gateway/kanban_dispatcher.py

📝 Walkthrough

Walkthrough

AgentsGenerator: extract YAML loading and workflow detection into _load_config and _is_workflow_yaml, early-return when missing, and route workflow-mode configs to _run_yaml_workflow/_arun_yaml_workflow; otherwise continue to the shared prepare/run path. KanbanDispatcher: log release_claim failures with traceback, fix subprocess log-file handle leak, and narrow shutdown exception handling (TimeoutExpired/OSError).

Changes

AgentsGenerator config & kickoff routing

Layer / File(s) Summary
Config loading and workflow detection
src/praisonai/praisonai/agents_generator.py
Added _load_config() to load/normalize YAML from agent_yaml or agent_file, alias '/app/api:app'/'api:app' to 'agents.yaml', return None when missing, and apply cli_config overrides. Added _is_workflow_yaml() to detect workflow-mode configs via process: workflow, steps+workflow, or type in (job, hybrid). Updated generate_crew_and_kickoff() and agenerate_crew_and_kickoff() to call _load_config(), early-return on None, and route workflow configs to _run_yaml_workflow() / _arun_yaml_workflow().

Error Handling and File-Handle Leak Fixes in KanbanDispatcher

Layer / File(s) Summary
Error logging for task claim release failures
src/praisonai/praisonai/gateway/kanban_dispatcher.py
dispatch_once() and _cleanup_completed_tasks() now catch release failures and log detailed errors containing task id/worker context and stack traces (exc_info=True) instead of silently ignoring them.
Worker subprocess file-handle fix and shutdown exception handling
src/praisonai/praisonai/gateway/kanban_dispatcher.py
_spawn_worker() creates a NamedTemporaryFile path then reopens the path and passes that handle to subprocess.Popen, closing the parent FD after start. _shutdown() handles subprocess.TimeoutExpired and OSError explicitly, logs SIGKILL escalation and kill failures, and clears tracked running tasks after termination attempts.

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

"🐰 I nudged the YAML, found the hidden cue,
I routed workflows where the runners do,
I closed the log door so descriptors roam no more,
I logged the slips so claims don't hide from view. 🥕"

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the three main categories of fixes: sync/async convergence in wrapper layer, kanban FD leak, and exception handling improvements.
Linked Issues check ✅ Passed Changes address all three objectives from issue #1863: sync/async consolidation via _load_config/_is_workflow_yaml, FD leak fix via proper file handle management, and exception handling improvements in kanban_dispatcher.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the three objectives: agents_generator.py updates for sync/async unification and kanban_dispatcher.py fixes for FD leak and exception handling.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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 claude/issue-1863-20260607-0813

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

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

@MervinPraison

Copy link
Copy Markdown
Owner Author

@copilot Do a thorough review of this PR. Read ALL existing reviewer comments above from Qodo, Coderabbit, and Gemini first — incorporate their findings.

Review areas:

  1. Bloat check: Are changes minimal and focused? Any unnecessary code or scope creep?
  2. Security: Any hardcoded secrets, unsafe eval/exec, missing input validation?
  3. Performance: Any module-level heavy imports? Hot-path regressions?
  4. Tests: Are tests included? Do they cover the changes adequately?
  5. Backward compat: Any public API changes without deprecation?
  6. Code quality: DRY violations, naming conventions, error handling?
  7. Address reviewer feedback: If Qodo, Coderabbit, or Gemini flagged valid issues, include them in your review
  8. Suggest specific improvements with code examples where possible

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown

Greptile Summary

This PR centralises config loading and workflow-type detection into _load_config / _is_workflow_yaml helpers, eliminating duplicated sync/async setup logic, and fixes a parent file-descriptor leak in the kanban dispatcher's Popen call. Exception handling across the dispatcher is tightened from bare except: to typed catches (TimeoutExpired, OSError) with structured error logging.

  • agents_generator.py: _load_config now correctly applies _merge_cli_config on both the agent_yaml and file-path branches (fixing the CLI-override regression flagged in review), and _is_workflow_yaml encapsulates the routing predicate — though it also adds a new type: job/type: hybrid routing condition that was absent from both the original sync and async paths.
  • kanban_dispatcher.py: wrapping open() in a with block before passing it to Popen closes the parent FD immediately after process creation; _shutdown now differentiates TimeoutExpired vs OSError and guards each kill() call against its own OSError, letting signals like KeyboardInterrupt propagate correctly.

Confidence Score: 5/5

Safe to merge; the kanban dispatcher fixes are straightforward and correct, and the config-loading refactor properly restores CLI-override merging for both YAML branches.

The two concrete bugs addressed (FD leak and CLI-merge regression) are correctly fixed. The narrowed exception handling in the dispatcher is a clean improvement. The only item worth a second look is the undocumented addition of type: job / type: hybrid routing in _is_workflow_yaml, which changes dispatch behaviour for any config using those keys — but this is likely intentional and does not break existing configs that relied solely on process: workflow or steps+workflow sections.

agents_generator.py — confirm whether the type: job / type: hybrid routing addition in _is_workflow_yaml is intentional; if so, a brief docstring note would clarify intent for future readers.

Important Files Changed

Filename Overview
src/praisonai/praisonai/agents_generator.py Extracts _load_config and _is_workflow_yaml helpers to DRY up sync/async paths and fixes the CLI-config-merge regression; the new workflow_type routing condition is an unannounced behavioral expansion.
src/praisonai/praisonai/gateway/kanban_dispatcher.py Fixes the parent-FD leak on Popen, narrows bare except: to TimeoutExpired/OSError with proper logging, and guards kill() calls against OSError — all straightforward and correct.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["generate_crew_and_kickoff / agenerate_crew_and_kickoff"] --> B["_load_config()"]
    B --> C{agent_yaml set?}
    C -- Yes --> D["yaml.safe_load(agent_yaml)"]
    C -- No --> E["open(agent_file) yaml.safe_load"]
    E -- FileNotFoundError --> F["print error, return None"]
    D --> G["cli_config? _merge_cli_config"]
    E --> G
    G --> H{config is None?}
    H -- Yes --> I["return silent"]
    H -- No --> J["_is_workflow_yaml(config)"]
    J -- process==workflow OR steps+workflow OR type job/hybrid --> K["_run_yaml_workflow / _arun_yaml_workflow"]
    J -- otherwise --> L["_prepare_for_run(config)"]
    L --> M["adapter.run / adapter.arun"]
Loading

Reviews (3): Last reviewed commit: "fix: wrapper layer gaps - CLI config reg..." | Re-trigger Greptile

@MervinPraison

Copy link
Copy Markdown
Owner Author

@claude You are the Lead Engineer. If the branch is under MervinPraison/PraisonAI (not a fork), you are able to make modifications to this branch and push directly. SCOPE: Focus ONLY on Python packages (praisonaiagents, praisonai). Do NOT modify praisonai-rust or praisonai-ts. Read ALL analysis and reviews above carefully (Gemini, CodeRabbit, Qodo, Copilot, etc).

Phase 1: Review per AGENTS.md

  1. Protocol-driven: check heavy implementations vs core SDK
  2. Backward compatible: ensure zero feature regressions
  3. Performance: no hot-path regressions

Phase 2: FIX Valid Issues
4. For any VALID bugs or architectural flaws found by Gemini, CodeRabbit, Qodo, Copilot, or any other reviewer: implement the fix
5. Push all code fixes directly to THIS branch (do NOT create a new PR)
6. Comment a summary of exact files modified and what you skipped

Phase 3: Final Verdict
7. If all issues are resolved, approve the PR / close the Issue
8. If blocking issues remain, request changes / leave clear action items

Comment thread src/praisonai/praisonai/agents_generator.py
Comment thread src/praisonai/praisonai/agents_generator.py Outdated
Comment thread src/praisonai/praisonai/gateway/kanban_dispatcher.py Outdated
@praisonai-triage-agent

praisonai-triage-agent Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MervinPraison's task —— View job


Phase 1: Architecture Review & Analysis ✅

Todo List:

  • Read AGENTS.md for architecture guidelines
  • Review PR changes against architecture rules
  • Fix CLI config regression in agents_generator.py (Priority 1 - Greptile finding)
  • Fix docstring mismatch in agents_generator.py (Priority 2 - Greptile finding)
  • Fix OSError handling in kanban_dispatcher.py (Priority 2 - Greptile finding)
  • Test changes
  • Push fixes to branch
  • Final verdict

✅ All Valid Issues Fixed

Issue 1: CLI Config Regression (Priority 1) - FIXED

Problem: Lines 474-486 - CLI config only merged when loading from file, not when agent_yaml provided directly
Impact: CLI overrides like --model, --framework silently ignored when YAML passed as string
Solution: Restructured _load_config() to apply _merge_cli_config() to both code paths

# Before: CLI config only merged for file path
if self.cli_config:
    self._merge_cli_config(config, self.cli_config)  # Only inside file branch

# After: CLI config merged for both paths  
if self.cli_config:
    self._merge_cli_config(config, self.cli_config)  # Outside conditional

Issue 2: Docstring Mismatch (Priority 2) - FIXED

Problem: Line 562 docstring claimed 5-tuple return, line 633 returned 4-tuple
Impact: Developer confusion, incorrect unpacking expectations
Solution: Corrected docstring to match actual 4-tuple return: (adapter, topic, tools_dict, config)

Issue 3: OSError in process.kill() (Priority 2) - FIXED

Problem: Lines 350, 357 - unguarded process.kill() calls could raise OSError if process already exited
Impact: Exception could leave subsequent tasks un-terminated during shutdown
Solution: Wrapped all process.kill() calls in try-except blocks with proper error logging

🎯 Architecture Compliance Analysis

✅ AGENTS.md Compliance:

  • Protocol-driven: Changes in wrapper layer (praisonai), not core SDK ✅
  • Backward compatible: Same public API, no breaking changes ✅
  • Performance-first: No new dependencies or hot-path regressions ✅
  • Agent-centric: Maintains focus on agent execution and workflows ✅

✅ Refactoring Quality:

  • DRY principle: Successfully eliminated 100+ lines of duplication ✅
  • Code consolidation: Shared _prepare_run() logic between sync/async paths ✅
  • Bug fixes: Addressed file descriptor leak and exception handling ✅

✅ Security Review:

  • No hardcoded secrets or unsafe eval/exec ✅
  • Input validation preserved ✅
  • No privilege escalation vectors ✅

🚀 Final Verdict: APPROVE

Summary of Changes:

  • Fixed critical regression where CLI config was silently dropped for agent_yaml usage
  • Fixed documentation mismatch that could confuse developers
  • Fixed resource leak and exception handling in worker shutdown
  • Maintained backward compatibility throughout

What was NOT changed:

  • Core SDK (praisonai-agents) - out of scope as requested ✅
  • External packages (praisonai-rust, praisonai-ts) - skipped as requested ✅
  • Public APIs - preserved for backward compatibility ✅

Test Status: Syntax validation passed. Full integration testing deferred to CI pipeline.

Recommendation:Merge this PR
All valid reviewer feedback has been addressed. The refactoring successfully eliminates code duplication while fixing genuine bugs. Changes follow architectural guidelines and maintain backward compatibility.


📁 Files Modified: praisonai/agents_generator.py, praisonai/gateway/kanban_dispatcher.py
🔗 Branch: claude/issue-1863-20260607-0813

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/praisonai/praisonai/gateway/kanban_dispatcher.py (1)

154-165: 📐 Maintainability & Code Quality | 💤 Low value

The FD leak fix is correct, but the temp file creation pattern has a minor inefficiency.

The two-step approach (create temp file for path, then reopen) works but creates an unnecessary race window. A cleaner pattern would be to pass the file handle directly to Popen:

with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.log') as temp_log:
    temp_log_path = temp_log.name
    process = subprocess.Popen(
        cmd,
        env=env,
        stdout=temp_log,
        stderr=subprocess.STDOUT,
        text=True
    )

This avoids reopening the file and eliminates the TOCTOU window. The current implementation is functional and fixes the leak as intended, so this is optional.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/praisonai/praisonai/gateway/kanban_dispatcher.py` around lines 154 - 165,
Replace the two-step temp file creation and reopen with using the
NamedTemporaryFile handle directly when launching the subprocess: keep the
tempfile.NamedTemporaryFile(...) as temp_log, capture temp_log.name into
temp_log_path if still needed, and pass temp_log as stdout to
subprocess.Popen(cmd, env=env, stdout=temp_log, stderr=subprocess.STDOUT,
text=True) in the kanban_dispatcher.py block (use the existing temp_log,
temp_log_path, cmd and env symbols) to avoid reopening the file and the TOCTOU
window while preserving the FD-leak fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/praisonai/praisonai/agents_generator.py`:
- Around line 488-493: The _is_workflow_yaml predicate misses top-level
type-based workflows so YAMLs with type: "job" or "hybrid" are treated as
adapter mode; update the _is_workflow_yaml(config) function to also return True
when config.get('type') is 'job' or 'hybrid' (in addition to the existing
checks) so generate_crew_and_kickoff and agenerate_crew_and_kickoff route them
to the workflow executor; preserve the current process/type/steps/workflow logic
and add the extra type check to the boolean expression.
- Around line 474-485: The method currently returns
yaml.safe_load(self.agent_yaml) early, skipping CLI overrides; change the flow
in the agents_generator.py load routine (the code handling self.agent_yaml and
self.agent_file) to parse self.agent_yaml into a local config variable instead
of returning immediately, then call self._merge_cli_config(config,
self.cli_config) when self.cli_config is present, and finally return the merged
config; keep the existing file-path fallback logic (self.agent_file) unchanged.

---

Nitpick comments:
In `@src/praisonai/praisonai/gateway/kanban_dispatcher.py`:
- Around line 154-165: Replace the two-step temp file creation and reopen with
using the NamedTemporaryFile handle directly when launching the subprocess: keep
the tempfile.NamedTemporaryFile(...) as temp_log, capture temp_log.name into
temp_log_path if still needed, and pass temp_log as stdout to
subprocess.Popen(cmd, env=env, stdout=temp_log, stderr=subprocess.STDOUT,
text=True) in the kanban_dispatcher.py block (use the existing temp_log,
temp_log_path, cmd and env symbols) to avoid reopening the file and the TOCTOU
window while preserving the FD-leak fix.
🪄 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: b125980d-16a3-45f3-b28f-8d8e8af1ba91

📥 Commits

Reviewing files that changed from the base of the PR and between 6f2df7d and 9d099c7.

📒 Files selected for processing (2)
  • src/praisonai/praisonai/agents_generator.py
  • src/praisonai/praisonai/gateway/kanban_dispatcher.py

Comment thread src/praisonai/praisonai/agents_generator.py
Comment on lines +488 to +493
def _is_workflow_yaml(self, config):
"""Check if configuration is workflow mode YAML."""
process_type = config.get('process', 'sequential')
has_steps = 'steps' in config
has_workflow_config = 'workflow' in config

if process_type == 'workflow' or (has_steps and has_workflow_config):
# Route to YAMLWorkflowParser for advanced workflow patterns
return self._run_yaml_workflow(config)

# Canonical format conversion: 'agents' -> 'roles', 'instructions' -> 'backstory'
# This ensures backward compatibility while supporting the new canonical format
if 'agents' in config and 'roles' not in config:
config['roles'] = {}
for agent_name, agent_config in config['agents'].items():
role_config = dict(agent_config) if agent_config else {}
# Convert 'instructions' to 'backstory' if present
# Note: preserve 'instructions' key for adapters that pass it to PraisonAgent
if 'instructions' in role_config and 'backstory' not in role_config:
role_config['backstory'] = role_config['instructions']
# Ensure required fields have defaults
if 'role' not in role_config:
role_config['role'] = agent_name.replace('_', ' ').title()
if 'goal' not in role_config:
role_config['goal'] = role_config.get('backstory', 'Complete the assigned task')
if 'backstory' not in role_config:
role_config['backstory'] = f'You are a {role_config["role"]}'
config['roles'][agent_name] = role_config
return process_type == 'workflow' or (has_steps and has_workflow_config)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Recognize type: job / type: hybrid as workflow YAML.

This predicate is now the gate for both generate_crew_and_kickoff() and agenerate_crew_and_kickoff(), but it misses the workflow shapes that the CLI routes by top-level type. A job or hybrid YAML without process: workflow will drop into the adapter path instead of the workflow executor.

Suggested fix
 def _is_workflow_yaml(self, config):
     """Check if configuration is workflow mode YAML."""
     process_type = config.get('process', 'sequential')
     has_steps = 'steps' in config
     has_workflow_config = 'workflow' in config
-    return process_type == 'workflow' or (has_steps and has_workflow_config)
+    workflow_type = config.get('type')
+    return (
+        process_type == 'workflow'
+        or (has_steps and has_workflow_config)
+        or workflow_type in {'job', 'hybrid'}
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/praisonai/praisonai/agents_generator.py` around lines 488 - 493, The
_is_workflow_yaml predicate misses top-level type-based workflows so YAMLs with
type: "job" or "hybrid" are treated as adapter mode; update the
_is_workflow_yaml(config) function to also return True when config.get('type')
is 'job' or 'hybrid' (in addition to the existing checks) so
generate_crew_and_kickoff and agenerate_crew_and_kickoff route them to the
workflow executor; preserve the current process/type/steps/workflow logic and
add the extra type check to the boolean expression.

@MervinPraison

Copy link
Copy Markdown
Owner Author

@claude Rebase conflict ping (fresh)

Please rebase onto origin/main, resolve the conflicts below, then git push --force-with-lease and confirm CI is green.

Conflicts (merge-tree vs origin/main):

  • src/praisonai/praisonai/agents_generator.py — main moved run prep to _prepare_for_run; keep your sync/async convergence, kanban FD leak fix, and exception-handling changes inside that shared path (avoid reviving deleted duplicate methods).

Do not merge; reply here when rebased and checks pass.

@praisonai-triage-agent

praisonai-triage-agent Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MervinPraison's task —— View job


✅ Rebase onto origin/main completed successfully

Todo List:

  • Fetch latest origin/main changes
  • Read current agents_generator.py to understand structure
  • Perform rebase onto origin/main
  • Resolve conflicts while preserving sync/async convergence logic
  • Ensure kanban FD leak fix and exception handling are maintained
  • Force push with lease
  • Confirm CI passes

✅ All Tasks Completed Successfully

Rebase Summary:

  • Successfully rebased onto origin/main
  • Resolved all conflicts while preserving functionality
  • Force pushed changes with --force-with-lease
  • All CI checks passing (review, test-windows, GitGuardian, CodeRabbit)

Key Fixes Applied During Rebase:

  1. CLI Config Regression - Fixed _load_config() to apply CLI overrides for both agent_yaml and agent_file paths
  2. Workflow Type Detection - Enhanced _is_workflow_yaml() to recognize type: job and type: hybrid workflows
  3. File Descriptor Leak - Preserved kanban dispatcher FD leak fix with proper context management
  4. Exception Handling - Maintained improved OSError handling in worker process termination

Sync/Async Convergence Status:
Main branch already had implemented our core improvements via _prepare_for_run() method, so our changes were successfully integrated into the existing architecture.

Ready for merge - All conflicts resolved, CI green ✅


📁 Branch: claude/issue-1863-20260607-0813
🔗 Job Run: https://github.com/MervinPraison/PraisonAI/actions/runs/27449463047

praisonai-triage-agent Bot and others added 2 commits June 12, 2026 23:46
…on, cli_backend support (fixes #1863)

* Fix sync/async path divergence in agents_generator.py
  - Extract shared _prepare_run() method consolidating ~150 lines of duplicate logic
  - Ensure both sync and async paths call adapter.resolve(), init_observability(), adapter.setup()
  - Add AgentOps initialization and AutoGen version selection to both paths
  - Remove behavioral drift between run() and arun()

* Fix file handle leak in kanban_dispatcher.py
  - Replace inline open() with proper context manager in _spawn_worker()
  - Parent FD now closes immediately after Popen(), preventing slow leaks

* Fix bare except clauses in kanban_dispatcher.py
  - Replace bare except: with specific exception handling
  - Add comprehensive error logging with task context
  - Allow KeyboardInterrupt/SystemExit/CancelledError to propagate for clean shutdown

Co-authored-by: MervinPraison <MervinPraison@users.noreply.github.com>
…OSError handling

- Fix CLI config regression: _merge_cli_config now applies to both agent_yaml and agent_file paths (fixes #1863)
- Fix docstring mismatch: _prepare_run returns 4-tuple not 5-tuple
- Fix OSError handling: guard process.kill() calls in kanban dispatcher shutdown

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wrapper layer gaps: sync/async path divergence, file-handle leak in kanban dispatcher, swallowed errors blocking task release

1 participant