Skip to content

Feature/Break Launch Process#78

Open
bbolek-ap wants to merge 10 commits intoandresharpe:mainfrom
bbolek-ap:feature/break_launch_process
Open

Feature/Break Launch Process#78
bbolek-ap wants to merge 10 commits intoandresharpe:mainfrom
bbolek-ap:feature/break_launch_process

Conversation

@bbolek-ap
Copy link
Contributor

Resolves: https://github.com/andresharpe/dotbot/blob/claude/dotbot-refactor-planning-kKO9U/docs/DOTBOT-V4-phase-03-launch-process-breakup.md

This pull request introduces a new modular process registry and a dedicated analysis process type for the runtime system. The main changes are the addition of a reusable PowerShell module for process registry operations (including locking, logging, and diagnostics), and a new Invoke-AnalyseProcess implementation that formalizes and automates the product analysis workflow for existing projects.

Process Registry Module Enhancements:

  • Added ProcessRegistry.psm1 module providing reusable functions for process management, including process file CRUD, activity logging, lock handling, diagnostics, and preflight checks. These functions support robust process tracking and coordination in the runtime environment.
  • Exported key functions such as New-ProcessId, Write-ProcessFile, Write-ProcessActivity, Test-ProcessLock, Set-ProcessLock, Remove-ProcessLock, and Test-Preflight for use across the system.

Analysis Process Implementation:

  • Introduced Invoke-AnalyseProcess.ps1, which defines a new process type for analyzing an existing codebase and generating foundational product documents (mission.md, tech-stack.md, entity-model.md). The function orchestrates the workflow, manages process state, and logs activity.
  • The analysis process includes a comprehensive prompt for the language model, ensures all required documents are created, and updates process status and logs throughout execution.

These changes lay the groundwork for robust, modular process management and standardized, automated analysis workflows in the runtime system.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the runtime launch flow into a modular “process registry + process type handlers” architecture, and adds a dedicated analyse process for scanning an existing repo and generating foundational product documents.

Changes:

  • Introduces reusable runtime modules for process persistence/logging/locking (ProcessRegistry.psm1) and shared task-loop helpers (TaskLoop.psm1).
  • Splits the previously monolithic launch-process.ps1 logic into process-type implementations (analysis/execution/workflow/kickstart/prompt/analyse) and dispatches by -Type.
  • Adds an Invoke-AnalyseProcess process type that prompts the model to scan an existing repository and write mission.md, tech-stack.md, and entity-model.md.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
profiles/default/systems/runtime/modules/TaskLoop.psm1 New shared helpers for YAML front matter, task selection, deadlock detection, and the interview loop.
profiles/default/systems/runtime/modules/ProcessTypes/Invoke-WorkflowProcess.ps1 New unified “analyse then execute” workflow process implementation.
profiles/default/systems/runtime/modules/ProcessTypes/Invoke-PromptProcess.ps1 New prompt-only process handler for planning/commit/task-creation flows.
profiles/default/systems/runtime/modules/ProcessTypes/Invoke-KickstartProcess.ps1 New kickstart pipeline handler with phase tracking and optional workflow spawning.
profiles/default/systems/runtime/modules/ProcessTypes/Invoke-ExecutionProcess.ps1 New execution loop handler (worktrees, retries, completion checks, merge).
profiles/default/systems/runtime/modules/ProcessTypes/Invoke-AnalysisProcess.ps1 New analysis loop handler for task analysis (rate limit handling, status transitions).
profiles/default/systems/runtime/modules/ProcessTypes/Invoke-AnalyseProcess.ps1 New “analyse existing repo” handler that generates core product documents.
profiles/default/systems/runtime/modules/ProcessRegistry.psm1 New module for process ID creation, process file writing, activity logging, locking, diagnostics, and preflight checks.
profiles/default/systems/runtime/launch-process.ps1 Updated to import the new modules/handlers, remove inlined helpers, and dispatch by process type.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +630 to +636
if ($mergeResult.push_result.success) {
Write-ProcessActivity -Id $ProcId -ActivityType "text" -Message "Pushed to remote: $($task.name)" -ProcessesDir $ProcessesDir
} else {
Write-Status "Push failed: $($mergeResult.push_result.error)" -Type Warning
Write-ProcessActivity -Id $ProcId -ActivityType "text" -Message "Push failed after merge: $($mergeResult.push_result.error)" -ProcessesDir $ProcessesDir
}
}
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

Write-Status's -Type ValidateSet does not include Warning, so this call will throw and can interrupt workflow completion (especially after a successful merge when only the push failed). Use -Type Warn (or expand Write-Status to support Warning).

Suggested change
if ($mergeResult.push_result.success) {
Write-ProcessActivity -Id $ProcId -ActivityType "text" -Message "Pushed to remote: $($task.name)" -ProcessesDir $ProcessesDir
} else {
Write-Status "Push failed: $($mergeResult.push_result.error)" -Type Warning
Write-ProcessActivity -Id $ProcId -ActivityType "text" -Message "Push failed after merge: $($mergeResult.push_result.error)" -ProcessesDir $ProcessesDir
}
}
if ($mergeResult.push_result.success) {
Write-ProcessActivity -Id $ProcId -ActivityType "text" -Message "Pushed to remote: $($task.name)" -ProcessesDir $ProcessesDir
} else {
Write-Status "Push failed: $($mergeResult.push_result.error)" -Type Warn
Write-ProcessActivity -Id $ProcId -ActivityType "text" -Message "Push failed after merge: $($mergeResult.push_result.error)" -ProcessesDir $ProcessesDir
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +103 to +131
function Test-ProcessLock {
[CmdletBinding()]
[OutputType([bool])]
param(
[Parameter(Mandatory)][string]$LockType,
[Parameter(Mandatory)][string]$ControlDir
)
$lockPath = Join-Path $ControlDir "launch-$LockType.lock"
if (-not (Test-Path $lockPath)) { return $false }
$lockContent = Get-Content $lockPath -Raw -ErrorAction SilentlyContinue
if (-not $lockContent) { return $false }
try {
Get-Process -Id ([int]$lockContent.Trim()) -ErrorAction Stop | Out-Null
return $true
} catch {
Remove-Item $lockPath -Force -ErrorAction SilentlyContinue
return $false
}
}

function Set-ProcessLock {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$LockType,
[Parameter(Mandatory)][string]$ControlDir
)
$lockPath = Join-Path $ControlDir "launch-$LockType.lock"
$PID.ToString() | Set-Content $lockPath -NoNewline -Encoding utf8NoBOM
}
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

The lock implementation is not atomic: two processes can both pass Test-ProcessLock and then both call Set-ProcessLock, allowing concurrent runs and/or having one process remove another's lock in cleanup. Consider creating the lock file atomically (e.g., open with FileMode.CreateNew / New-Item -ErrorAction Stop) and making Remove-ProcessLock verify the PID matches the current process before deleting.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +40
function Write-ProcessFile {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$Id,
[Parameter(Mandatory)][hashtable]$Data,
[Parameter(Mandatory)][string]$ProcessesDir
)
$filePath = Join-Path $ProcessesDir "$Id.json"
$tempFile = "$filePath.tmp"

$maxRetries = 3
for ($r = 0; $r -lt $maxRetries; $r++) {
try {
$Data | ConvertTo-Json -Depth 10 | Set-Content -Path $tempFile -Encoding utf8NoBOM -NoNewline
Move-Item -Path $tempFile -Destination $filePath -Force -ErrorAction Stop
return
} catch {
if (Test-Path $tempFile) { Remove-Item $tempFile -Force -ErrorAction SilentlyContinue }
if ($r -lt ($maxRetries - 1)) {
Start-Sleep -Milliseconds (50 * ($r + 1))
} else {
Write-Diag -Msg "Write-ProcessFile FAILED for $Id after $maxRetries retries: $_" -DiagLogPath $script:DiagLogPath
}
}
}
}
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

Write-ProcessFile silently gives up after exhausting retries (it only logs to diag). Callers assume the process state was persisted, so a write failure can lead to a running process with no/partial registry state and hard-to-debug behavior. Consider throwing a terminating error after the final retry (or returning a success flag that callers must check).

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +21
$existing = Get-Content $FilePath -Raw
($yaml + $existing) | Set-Content -Path $FilePath -Encoding utf8NoBOM -NoNewline
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

Add-YamlFrontMatter always prepends a new front matter block without checking whether one already exists. Re-running kickstart phases (or re-generating docs) can produce duplicated --- blocks, which many front-matter parsers treat as invalid/ambiguous. Consider detecting an existing front-matter header at the start of the file and replacing/merging instead of blindly prepending.

Suggested change
$existing = Get-Content $FilePath -Raw
($yaml + $existing) | Set-Content -Path $FilePath -Encoding utf8NoBOM -NoNewline
$existing = Get-Content -Path $FilePath -Raw
# If the file already starts with a YAML front matter block, replace it;
# otherwise, prepend the new front matter.
$newContent = $null
if ($existing) {
# Normalize line splitting across different newline conventions
$lines = $existing -split "(`r`n|`n|`r)"
if ($lines.Length -gt 0 -and $lines[0].Trim() -eq '---') {
# Find the closing '---' that terminates the existing front matter
$closingIndex = $null
for ($i = 1; $i -lt $lines.Length; $i++) {
if ($lines[$i].Trim() -eq '---') {
$closingIndex = $i
break
}
}
if ($null -ne $closingIndex) {
# Preserve everything after the existing front matter block
if ($closingIndex -lt ($lines.Length - 1)) {
$bodyLines = $lines[($closingIndex + 1)..($lines.Length - 1)]
$body = ($bodyLines -join "`n")
} else {
$body = ""
}
$newContent = $yaml + $body
}
}
}
if ($null -eq $newContent) {
# No existing, well-formed leading front matter detected; prepend ours.
$newContent = $yaml + $existing
}
$newContent | Set-Content -Path $FilePath -Encoding utf8NoBOM -NoNewline

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +92
try {
$streamArgs = @{
Prompt = $fullPrompt
Model = $ClaudeModelName
SessionId = $ClaudeSessionId
PersistSession = $false
}
if ($ShowDebug) { $streamArgs['ShowDebugJson'] = $true }
if ($ShowVerbose) { $streamArgs['ShowVerbose'] = $true }

Invoke-ProviderStream @streamArgs

$processData.status = 'completed'
$processData.completed_at = (Get-Date).ToUniversalTime().ToString("o")
$processData.heartbeat_status = "Completed: $Description"
} catch {
$processData.status = 'failed'
$processData.failed_at = (Get-Date).ToUniversalTime().ToString("o")
$processData.error = $_.Exception.Message
$processData.heartbeat_status = "Failed: $($_.Exception.Message)"
Write-Status "Process failed: $($_.Exception.Message)" -Type Error
}

Write-ProcessFile -Id $ProcId -Data $processData -ProcessesDir $ProcessesDir
Write-ProcessActivity -Id $ProcId -ActivityType "text" -Message "Process $ProcId finished ($($processData.status))" -ProcessesDir $ProcessesDir
}
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

This process uses a provider session ID but never calls Remove-ProviderSession. Other process types clean up session artifacts (e.g., task analysis/execution), so repeated runs of prompt-based processes can accumulate stale session data under the provider's local storage (Claude: ~/.claude/projects/...). Consider adding a ProjectRoot parameter (or deriving it from BotRoot) and cleaning up the session in a finally block.

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +127
$streamArgs = @{
Prompt = $analysePrompt
Model = $ClaudeModelName
SessionId = $ClaudeSessionId
PersistSession = $false
}
if ($ShowDebug) { $streamArgs['ShowDebugJson'] = $true }
if ($ShowVerbose) { $streamArgs['ShowVerbose'] = $true }

Invoke-ProviderStream @streamArgs

# Verify product docs were created
$hasDocs = (Test-Path (Join-Path $productDir "mission.md")) -and
(Test-Path (Join-Path $productDir "tech-stack.md")) -and
(Test-Path (Join-Path $productDir "entity-model.md"))

if (-not $hasDocs) {
throw "Analyse failed: product documents were not created"
}

Write-ProcessActivity -Id $ProcId -ActivityType "text" -Message "Analyse complete - product documents created" -ProcessesDir $ProcessesDir

$processData.status = 'completed'
$processData.completed_at = (Get-Date).ToUniversalTime().ToString("o")
$processData.heartbeat_status = "Completed: $Description"
} catch {
$processData.status = 'failed'
$processData.failed_at = (Get-Date).ToUniversalTime().ToString("o")
$processData.error = $_.Exception.Message
$processData.heartbeat_status = "Failed: $($_.Exception.Message)"
Write-Status "Process failed: $($_.Exception.Message)" -Type Error
}

Write-ProcessFile -Id $ProcId -Data $processData -ProcessesDir $ProcessesDir
Write-ProcessActivity -Id $ProcId -ActivityType "text" -Message "Process $ProcId finished ($($processData.status))" -ProcessesDir $ProcessesDir
}
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

This process runs the provider with a session ID but never calls Remove-ProviderSession, so Claude session artifacts can accumulate over time. Consider cleaning up the session in a finally block after completion/failure (you can derive ProjectRoot from BotRoot if you don't want to thread it as a parameter).

Copilot uses AI. Check for mistakes.
if ($mergeResult.push_result.success) {
Write-ProcessActivity -Id $ProcId -ActivityType "text" -Message "Pushed to remote: $($task.name)" -ProcessesDir $ProcessesDir
} else {
Write-Status "Push failed: $($mergeResult.push_result.error)" -Type Warning
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

Write-Status only supports Type values {Info, Success, Error, Warn, Process, Complete} (see DotBotTheme.psm1). Using -Type Warning will trigger a parameter validation error at runtime, potentially breaking the post-merge push failure path. Use -Type Warn (or add Warning to Write-Status's ValidateSet if intentional).

Suggested change
Write-Status "Push failed: $($mergeResult.push_result.error)" -Type Warning
Write-Status "Push failed: $($mergeResult.push_result.error)" -Type Warn

Copilot uses AI. Check for mistakes.
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