# BobNet OS Architecture And Data Contracts ## Architecture Overview ```mermaid flowchart LR Owner["Owner"] --> UI["WinForms UI"] UI --> Store["Board Store / SQLite Kernel"] UI --> Chat["Chat Planner"] UI --> Dispatch["Dispatcher"] Chat --> Model["Local LLM / Ollama"] Chat --> Validator["Host Validator"] Validator --> Store Dispatch --> Runner["Codex Runner"] Runner --> Workspace["Direct / Scratch / Worktree Workspace"] Runner --> Result["BOBNETOS_RESULT.json"] Result --> Store CLI["CLI/API/MCP"] --> Store CLI --> Dispatch ``` ## Storage Roots Default user data root: ```text %LOCALAPPDATA%\BobNetOS ``` Configurable with: ```powershell $env:BOBNETOS_DATA_DIR = "C:\some\path" $env:BOBNETOS_STORE = "sqlite" ``` SQLite database file: ```text bobnetos.db ``` ## Canonical Statuses Use these exact status values in code and database: ```text Backlog Ready InProgress Blocked Review Done Archived ``` The UI may display `In Progress`, but persistence should use one canonical value. ## Core Tables The exact schema can evolve, but these entities are required. ### boards ```sql CREATE TABLE boards ( id TEXT PRIMARY KEY, name TEXT NOT NULL, workspace_path TEXT NOT NULL, goal TEXT NOT NULL DEFAULT '', is_archived INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); ``` ### cards ```sql CREATE TABLE cards ( id TEXT PRIMARY KEY, board_id TEXT NOT NULL, title TEXT NOT NULL, body TEXT NOT NULL DEFAULT '', status TEXT NOT NULL, assignee TEXT NOT NULL DEFAULT '', workspace_mode TEXT NOT NULL DEFAULT 'Direct', sort_order INTEGER NOT NULL DEFAULT 0, is_archived INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, FOREIGN KEY (board_id) REFERENCES boards(id) ON DELETE CASCADE ); ``` ### card_links ```sql CREATE TABLE card_links ( parent_card_id TEXT NOT NULL, child_card_id TEXT NOT NULL, created_at TEXT NOT NULL, PRIMARY KEY (parent_card_id, child_card_id) ); ``` Rules: - Parent and child must be on the same board. - A card cannot depend on itself. - Dependency cycles must be rejected. - A child in Backlog can promote to Ready only when all parents are Done. ### card_comments ```sql CREATE TABLE card_comments ( id TEXT PRIMARY KEY, board_id TEXT NOT NULL, card_id TEXT NOT NULL, author TEXT NOT NULL, body TEXT NOT NULL, created_at TEXT NOT NULL ); ``` ### card_runs ```sql CREATE TABLE card_runs ( id TEXT PRIMARY KEY, board_id TEXT NOT NULL, card_id TEXT NOT NULL, attempt INTEGER NOT NULL, status TEXT NOT NULL, profile TEXT NOT NULL, started_at TEXT NOT NULL, completed_at TEXT NULL, exit_code INTEGER NULL, result_path TEXT NOT NULL DEFAULT '', log_path TEXT NOT NULL DEFAULT '', summary TEXT NOT NULL DEFAULT '', error TEXT NOT NULL DEFAULT '', metadata_json TEXT NOT NULL DEFAULT '{}' ); ``` ### card_events ```sql CREATE TABLE card_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, board_id TEXT NOT NULL, card_id TEXT NULL, run_id TEXT NULL, kind TEXT NOT NULL, actor TEXT NOT NULL, summary TEXT NOT NULL, payload_json TEXT NOT NULL DEFAULT '{}', created_at TEXT NOT NULL ); ``` Event examples: ```text board.created card.created card.updated card.archived card.claimed card.promoted card.blocked card.completed run.created run.started run.heartbeat run.completed run.blocked run.failed run.timed_out hook.dispatched chat.proposal.created chat.proposal.approved ``` ### attachments ```sql CREATE TABLE card_attachments ( id TEXT PRIMARY KEY, board_id TEXT NOT NULL, card_id TEXT NOT NULL, source_path TEXT NOT NULL, stored_path TEXT NOT NULL, display_name TEXT NOT NULL, content_type TEXT NOT NULL DEFAULT '', created_at TEXT NOT NULL ); ``` ### automation and notifications Recurring automation and notification tables may vary, but must preserve: - Rule identity. - Board/card target. - Schedule/trigger. - Enabled/paused state. - Last run/next run timestamps. - Notification payload and read/dismissed state. ## Worker Context Contract Each run should create a run folder: ```text \.codex-harness\runs\\ BOBNETOS_CARD_CONTEXT.md BOBNETOS_RESULT.json ``` `BOBNETOS_CARD_CONTEXT.md` should include: - Board name and goal. - Card ID, title, body, status. - Assignee/profile prompt. - Workspace mode. - Parent handoff summaries. - Comments. - Attachments/evidence paths. - Required result protocol. ## Worker Result Contract Workers must write: ```json { "schema_version": 1, "card_id": "card_abc", "run_id": "run_abc", "status": "completed", "summary": "What changed and why.", "changed_files": ["path/to/file.cs"], "verification": ["dotnet test BobNetOS.sln -c Release --no-build"], "residual_risk": ["Manual UI smoke still needed."], "blocked_reason": null, "follow_up_cards": [], "comments": [] } ``` Allowed statuses: ```text completed blocked failed ``` Parsing rules: - Missing file means failed/blocked depending on runner outcome. - Invalid JSON must be captured as run error, not silently ignored. - `completed` maps to Review or Done depending review policy. - `blocked` maps to Blocked with durable reason. - `failed` increments failure count and may trip retry/circuit breaker. ## Dispatcher Contract Claiming must be atomic. A rough SQL shape: ```sql UPDATE cards SET status = 'InProgress', updated_at = @now WHERE id = @cardId AND board_id = @boardId AND status = 'Ready'; ``` The service must only create a run if the claim succeeds. Dispatcher loop responsibilities: - Promote eligible Backlog children to Ready. - Skip Ready children whose parents are not Done. - Claim Ready cards. - Create run row. - Build worker context. - Launch worker. - Parse result. - Write run/card/events. - Reclaim or block stale runs. - Avoid thrashing by blocking after repeated spawn failures. ## Workspace Modes ```text Direct: use board workspace. Scratch: create BobNet OS-owned empty run workspace under data root. Worktree: create git worktree under BobNet OS-owned workspace root. ``` Scratch and worktree folders must be clearly marked as BobNet OS-owned before cleanup. ## Local CLI/API/MCP Minimum CLI: ```text cli boards list/create/archive cli cards list/show/create/complete/block/comment/link/unlink cli runs list cli events list/tail cli dispatch once/loop cli orchestration status/decompose cli api serve cli mcp serve ``` Minimum API: ```text GET /health GET /api/boards POST /api/boards GET /api/boards/{boardId}/cards POST /api/boards/{boardId}/cards POST /api/boards/{boardId}/dispatch/once ``` API routes under `/api/*` require a local token header or bearer token. Minimum MCP tools should use BobNet OS names: ```text bobnetos_create_card bobnetos_complete_card bobnetos_block_card bobnetos_comment_card bobnetos_link_cards bobnetos_dispatch_once ```