# Multi-Agent System 2.0 Design **Goal:** Replace the current bash-script based worker system (`start-worker.sh`, etc.) with a robust, type-safe Haskell application `Omni/Agent.hs`. ## 1. CLI Interface The `agent` command (compiled from `Omni/Agent.hs`) will provide a unified interface for managing workers. ```bash agent start [--background] # Start a worker (foreground by default, background with flag) agent stop # Stop a background worker agent status # List all workers and their status agent log [-f] # View/tail worker logs agent sync # Sync local state with live (helper) ``` ## 2. Module Structure (`Omni/Agent/`) We will refactor the bash logic into Haskell modules: - **Omni.Agent** (`Omni/Agent.hs`): Main entry point and CLI parsing (Docopt). - **Omni.Agent.Core**: Core data types and state management. - **Omni.Agent.Worker**: The worker loop logic (sync, claim, work, submit). - **Omni.Agent.Git**: Git operations (worktree, branch, merge, commit). - **Omni.Agent.Process**: Process management (PID files, signals). - **Omni.Agent.Log**: Log streaming and filtering (the "monitor" logic). ## 3. Data Types ```haskell data WorkerStatus = Idle | Syncing | Working TaskId | Submitting TaskId | Error Text deriving (Show, Eq, Generic) data Worker = Worker { workerName :: Text , workerPid :: Maybe Int , workerStatus :: WorkerStatus , workerPath :: FilePath } ``` ## 4. Implementation Details ### 4.1 Worker Loop (`agent start`) The Haskell implementation should replicate the logic of `start-worker.sh` but with better error handling and logging. 1. **Setup**: Ensure worktree exists (or create it). 2. **Loop**: - `Git.syncWithLive` (Rebase-based to preserve local history) - `Task.sync` - `task <- Task.findReady` - If `task`: - `Task.claim task` - `baseBranch <- Git.determineBaseBranch task` (Check dependencies) - `Git.checkoutTaskBranch task baseBranch` (Force checkout to clean untracked files) - `Amp.execute prompt` - `Git.commit` - `Git.checkoutBase` - `Task.submitReview task` - Else: `sleep 60` ### 4.2 Process Management - Store PIDs in `.tasks/workers/.pid`. - `agent stop` sends SIGTERM to the PID. - `agent status` checks if PID is alive. ### 4.3 Logging - Continue writing raw Amp logs to `_/llm/amp.log` in the worker directory. - `agent log` reads this file and applies the filtering logic (currently in `monitor.sh` jq script) using Haskell (Aeson). - **UI Design**: - **Two-line Status**: The CLI should maintain two reserved lines at the bottom (or top) of the output for each worker: - **Line 1 (Meta)**: `[Worker: omni-worker-1] Task: t-123 | Files: 3 | Credits: $0.45 | Time: 05:23` - **Line 2 (Activity)**: `[14:05:22] 🤖 Thinking...` (updates in place) - **Task Details**: When claiming a task, print the full task description/details to the log/console so the user can see what is being worked on without looking it up. - **Completion**: When a task finishes, print a summary line (e.g., `[✓] Task t-123 completed in 12m 30s`) and a hard line break before starting the next loop. - **History**: Previous log lines (tool outputs, thoughts) scroll up above these two status lines. ### 4.5 Git Robustness (Learnings) - **Identity**: Configure `git config user.name "Omni Worker"` and `user.email` in the worktree to clearly distinguish worker commits from human commits. - **Force Checkout**: The worker must use `git checkout -f` (or equivalent) when switching to task branches to ensure untracked files (like `.tasks/counters.jsonl`) don't block the switch. - **Base Branch Logic**: - If the task depends on another task that is *not* yet in `live` (e.g., in `Review`), the worker should branch off the dependency's branch (`task/`). - Otherwise, branch off `live` directly. Do NOT use the local worker branch (`omni-worker-N`) as the base, as it may contain temporary sync commits that shouldn't be merged. - **Commit Hygiene**: Bundle the task status update (marking as 'Review') *inside* the feature implementation commit. This keeps the history clean (one commit per feature) and avoids separate "sync" commits for status changes. - **Clean State**: The worker should ensure the workspace is clean (no uncommitted changes) before starting a new loop iteration. - **Rebase Safety**: Always check the exit code of `git rebase`. If it fails (conflicts), abort immediately (`git rebase --abort`) to avoid leaving the repo in a broken interactive rebase state. - **Status Verification**: Verify that task status updates actually succeed. Check `task ready` output against `live` state to prevent "zombie" tasks (completed in live but stuck in local loop) from being re-claimed. - **Binary Freshness**: Ensure the `task` binary used by the worker is rebuilt/updated when source code changes, otherwise logic fixes (like `task ready` filtering) won't take effect. ## 5. Migration Strategy 1. **Parallel Existence**: Keep bash scripts while developing Haskell version. 2. **Feature Parity**: Ensure `agent start` works exactly like `start-worker.sh`. 3. **Cutover**: Update `WORKER_AGENT_GUIDE.md` to use `agent` command. 4. **Cleanup**: Delete bash scripts. ## 6. Testing Plan ### 6.1 Unit Tests (`Omni/Agent/Test.hs`) - Test `Git` module commands (mocked). - Test `Log` filtering logic. - Test CLI argument parsing. ### 6.2 Integration Tests - Create a temporary test repo. - Spawn a worker. - Mock `amp` binary (simple script that `echo "done"`). - Verify task moves from Open -> InProgress -> Review. ## 7. References - `Omni/Agent/start-worker.sh` (Current implementation) - `Omni/Task.hs` (Task manager integration)