Digital Staff Unified Architecture Solution (Consolidation of Diverse Components)
Goal: Unify the entire chain from 'Definition → Invocation (MTClaw Client-side / Self-developed Scheduler) → Execution (worker) → Mini Program End → External Official Website API'
into a single source of truth, eliminating the current fragmentation across multiple configuration files, databases, and scripts.
0. Current State Diagnosis (Verified Facts)
0.1 The Invocation Endpoint is Already Unified (Good News)
Three sets of invocation entry points all converge at runtime to the same function:
| Invocation Entry | Path | Endpoint |
|---|---|---|
| MTClaw Client-side Proxy | server.js:2062 /api/digital-staff/mtclaw/proxy → server.js:2358 _scheduler.runStaffOnce | boss-scheduler/index.js:99 runStaffOnce |
| Self-developed Scheduler | boss-scheduler/index.js runStaffOnce | lite-scheduler.js runOnce → _runWorker (actual worker execution) |
| Mini Program End | bossagents-miniapp/server/miniapp-routes.js:915 /api/digital-staff/run (axios call back to main entry) and :1136 direct require('../../server/boss-scheduler/index.js').runStaffOnce | Same runStaffOnce |
| External/Official Site/WeCom/Feishu | server.js /api/digital-staff/run + routes/open-platform.js / feishu-*.js | Same runStaffOnce |
→ The execution endpoint _runWorker is already the single source of truth; no need to recreate a scheduler.
0.2 The real chaos lies in the 'definition sources' and 'dead ends'.
- Three coexisting and conflicting definition sources:
- The staff section in profiles/local.yaml (54 entries, defining seeds) → syncStaffToDb writes to DB;
- staff-manager.js:345-361 seedDefaultStaff hardcodes 15 seeds (INSERT OR IGNORE), with fields inconsistent with local.yaml, inserting in parallel;
- 73 client-side scripts in MTClaw/scripts/*.js each hardcode a default DS-XXX staffId, among which 19 do not exist in local.yaml or workers (dead links).
- The runtime truth is DB over YAML: index.js:43 syncStaffToDb → :45 loadStaffFromDb overwrites memory with DB data. Modifying YAML without re-syncing won't take effect online, causing the confusing perception that "changes don't work."
- Seven basic verbs are not explicitly anchored: Identify/Create/Fix/Optimize/Compare/Generate/Inspect are scattered across different DS-XXX; Compare lacks a dedicated base employee; Optimize is split among three (DS-COST-001 / DS-PROCESS-OPT-001 / DS-SCCAPP-OPT-001).
- The web version only renders employee instances, not the positions system (roles like Factory Operator / Process Engineer / Warehouse Keeper are aligned but invisible on the frontend).
0.3 19 orphaned IDs (called by MTClaw client-side but no backend handler).
DS-ASSET-001 DS-BOM-001 DS-COMP-001 DS-CONTRACT-001 DS-ENERGY-001 DS-FIN-001 DS-HR-001 DS-INVOICE-001 DS-LOG-001 DS-MEET-001 DS-PROC-PLAN-001 DS-PROD-001 DS-QUALITY-001 DS-RISK-001 DS-SAFETY-001 DS-SUP-AUDIT-001 DS-TRAIN-001 DS-TRAVEL-001 DS-WH-001
These scripts return delegate_to_digital_staff, but there is no corresponding mapping for toolToStaff in server.js → runStaffOnce reports 'staff does not exist', which is a dead link.
1. Unified Architecture (Target State)
┌─────────────────────────────────────────────┐
定义真相源 │ profiles/local.yaml │
(唯一可编辑) │ staff: [所有数字员工定义] │
│ positions:[工厂岗位→员工映射] │
│ (七个基础动词显式锚定 verbs: Identify/Create/...) │
└───────────────┬─────────────────────────────┘
│ syncStaffToDb(一次性/重启时)
▼
┌─────────────────────────────────────────────┐
运行时镜像 │ SQLite digital_staff 表(仅镜像,不可手改) │
└───────────────┬─────────────────────────────┘
│ loadStaffFromDb(启动加载)
▼
┌─────────────────────────────────────────────┐
统一执行内核 │ boss-scheduler/index.js runStaffOnce │
│ → lite-scheduler._runWorker(唯一终点) │
│ → workers/*.js(唯一实现) │
└───────┬───────────────┬───────────────┬──────┘
│ │ │
┌─────────────┴──┐ ┌──────────┴────┐ ┌────────┴──────────┐
调用端 │ MTClaw 端侧 │ │ 自研调度器 │ │ 小程序 / 官网 / │
│ (L1路由→委托) │ │ (runStaffOnce)│ │ 企微/飞书/openapi │
└────────────────┘ └───────────────┘ └───────────────────┘
全部经 runStaffOnce 收敛,无第二套执行
铁律:
- Adding/modifying digital staff only modifies local.yaml; it is prohibited to write another copy in staff-manager.js, MTClaw scripts, or the database.
- All calling clients (including MTClaw client-side, mini-programs, and external APIs) must only use runStaffOnce; they are prohibited from forking the execution logic individually.
- workers/*.js are the only business implementations; MTClaw scripts never handle business logic, only L1 routing decisions.
2. Implementation Steps (in dependency order)
Step 1: Make local.yaml the single source of truth
- Delete all 15 hardcoded seed entries from lines 345-361 in staff-manager.js, and merge their responsibilities into the staff section of local.yaml (if a name already exists, verify the fields, with YAML taking precedence).
- Add a verbs: field to each staff entry in local.yaml, explicitly anchoring the seven basic verbs:
- Identify → DS-IDENTIFY-001
- Create → DS-SCSAI-001
- Repair → DS-REPAIR-001 (includes process data repair DS-PROC-DATA-001 under it)
- Optimize → Assign a unified primary staff (suggest DS-OPT-001 or designate DS-COST-001 as primary for cost optimization, label others as sub)
- Compare → Add a new independent base staff DS-COMPARE-001 (extract comparison capabilities from DS-CHIP-004 / DS-DOC-001 / DS-STAT-001)
- Generate → DS-CONTENT-001 (document generation falls under DS-DOC-001, labeled sub)
- Inspection → DS-INSPECT-001 (including inspection closed-loop DS-*)
- Define the 'base employee' marker as tier: base, for highlighting on the web version/official website.
Step 2: Close 19 dead-end IDs
For those 19 IDs in MTClaw/scripts without backend support, choose one of the following (unified decision):
- A (Recommended): Register these 19 employees in local.yaml and implement the corresponding workers/*.js (actually building 'asset management/contract/finance/HR/quality/safety/training/travel/warehousing...').
- B: Modify scripts to point to existing similar employees (e.g., DS-WH-001 → DS-STOCK-001, DS-QUALITY-001 → DS-INSPECT-001), without implementing them.
This step is mandatory; otherwise, the MTClaw client side will still have dead links.
Step 3: Use DB only as a runtime mirror, remove 'dual-write'
- After deleting staff-manager.seedDefaultStaff, syncStaffToDb becomes the sole entry point for writing to the DB; maintain the startup order: loadProfile → syncStaffToDb → loadStaffFromDb.
- The document clearly states: The database must not be manually modified; changes to the YAML take effect upon restart. Remove all scattered code that directly "INSERTs into digital_staff".
Step 4: Unify and converge the calling end
- MTClaw client-side: Scripts only perform L1 routing (keep the current state), but server.js's toolToStaff must cover all IDs registered in local.yaml (naturally satisfied after Step 2 completion).
- Mini-program side: Keep the two paths in miniapp-routes.js that go through runStaffOnce. Delete any direct calls that bypass runStaffOnce.
- External/Official Website: All entries for /api/digital-staff/run and open-platform / feishu must uniformly call runStaffOnce, without creating separate implementations.
Step 5: Web version simultaneously renders "Position System + Employee Instances"
- Add a "Position View" tab to the front-end digital staff page. Consume the existing /api/digital-staff/positions (from the positions section of local.yaml, which includes 16 positions such as Factory Operator, Process Technician, Warehouse Keeper for alignment). This allows the front-end to visualize the mapping of "Factory Operator → Corresponding Digital Staff".
Step 6: Remove the old dual implementation
- Confirm that the old runStaffOnce (switch-case dispatch) in server/digital-staff/index.js is no longer used by the server.js entry point (the loader now points to boss-scheduler), and delete it when appropriate to eliminate the dual execution implementation.
3. Verification Checklist (After Closure)
- [ ] grep the entire repository for INSERT ... digital_staff shows only the syncStaffToDb location remains.
- [ ] Hard-coded seed segments in staff-manager.js have been deleted.
- [ ] All DS-IDs referenced by the MTClaw 73 script are registered in local.yaml (0 orphaned references).
- [ ] Each of the seven basic verbs has a tier: base primary staff, with an independent DS-COMPARE-001 for comparison.
- [ ] The web version's "Position View" can display the digital employees corresponding to factory operators/process technicians/warehouse keepers.
- [ ] End-to-end: MTClaw client-side hit → runStaffOnce → _runWorker → actual database persistence, with no "employee does not exist" errors.
4. Key Document List
| Document | Role | Actions in This Solution |
|---|---|---|
| server/boss-scheduler/profiles/local.yaml | Single source of truth | Add verbs/basic employee tags, fill 19 missing ID implementations |
| server/boss-scheduler/staff-registry.js | syncStaffToDb sole DB writer | Keep as the only write entry point |
| server/boss-scheduler/index.js | runStaffOnce unified core | Keep |
| server/boss-scheduler/workers/*.js | Sole business logic implementation | Add 19 missing ID implementations as needed |
| server/digital-staff/staff-manager.js | Old hard-coded seed data | Delete seedDefaultStaff |
| server/digital-staff/index.js | Old runStaffOnce duplicate implementation | Delete (after confirming loader is unused) |
| MTClaw/scripts/*.js | L1 client-side routing | Only handle routing, align all IDs with local.yaml |
| bossagents-miniapp/server/miniapp-routes.js | Mini-program invocation | Only via runStaffOnce |
| server/routes/open-platform.js feishu-*.js | External/WeCom/Feishu | Only via runStaffOnce |
5. Implementation Progress (2026-08-22, 1+3+A completed)
Completed
- Step 3 (Definition Source Consolidation): The hardcoded 15 seed entries in seedDefaultStaff() in server/digital-staff/staff-manager.js have been removed, replaced by backfillLegacyStaff() (which only backfills empty worker fields in the legacy database based on local.yaml, without inserting any new employees). Digital staff definitions are now solely written via syncStaffToDb → staffManager.createStaff/updateStaff, eliminating dual definition with YAML.
- Step 1 (Seven-Verb Anchoring): Added tier: base and verbs: fields to local.yaml, anchoring all seven core verbs:
- Identify=DS-IDENTIFY-001 (new), Create=DS-SCSAI-001, Repair=DS-REPAIR-001 (new), Optimize=DS-COST-001, Compare=DS-COMPARE-001 (new), Generate=DS-CONTENT-001, Inspect=DS-INSPECT-001 (new).
- The four previously missing basic employees IDENTIFY/REPAIR/INSPECT/COMPARE have been supplemented with registration and paired with workers.
- Step 2A (Repairing 19 broken heads): Register 19 originally broken MTClaw employees (DS-ASSET/BOM/COMP/CONTRACT/ENERGY/FIN/HR/INVOICE/LOG/MEET/PROC-PLAN/PROD/QUALITY/RISK/SAFETY/SUP-AUDIT/TRAIN/TRAVEL/WH-001) in local.yaml, each with complete fields + tier: domain; register 23 new workers in the WORKERS table of lite-scheduler.js mapping to them (4 basic + 19 broken heads), and generate corresponding 23 minimal usable worker files (workers/{identify,repair,inspect,compare,asset,bom,...}.js, skeleton implementation, following the principle of honesty, pending real domain logic).
Verification result
- All 49 DS-IDs referenced by the 73 MTClaw scripts are registered in local.yaml, 0 broken heads (the original 19 broken heads have been cleared).
- local.yaml parsed successfully, total staff count 77 (54 original + 4 base new + 19 stub new).
- All 23 new worker files can be loaded and export run(), WORKERS mapping is complete.
- staff-manager.js full warehouse INSERT into digital_staff now only has createStaff (entry point syncStaffToDb), hardcoded seeds have been eradicated.
Pending (Next Steps)
- Step 2A's 19 domain workers (asset/bom/compliance/contract/energy/finance/hr/invoice/logistics/meeting/proc-plan/production/quality/risk/safety/sup-audit/training/travel/warehouse) remain skeletons, have been made honest (returning success:false + implemented:'skeleton' when no real logic exists, no longer pretending success). Real logic will be filled in for each domain as needed later.
- Step 6: Delete the old dual implementation of runStaffOnce in server/digital-staff/index.js (after confirming the loader is unused, low risk, only keep staffLog/mergeDbIntoMemory utility functions).
Deployed (2026-08-22, second batch).
- Four-verb base real degradation implementation: The four seven-verb workers—identify/compare/inspect/repair—have been filled with real, executable logic (based on read-only SELECT from ctx.db + parameter input for identification/comparison/inspection/repair diagnosis, capable of real work or honest degradation when MTClaw is unavailable). Runtime verification passed.
- 19 domain skeletons made honest: Removed the "always success:true" facade; explicitly marked success:false when no real logic exists, eliminating false successes.
- Verification: All 23 workers can be loaded and exported for run(); 4-verb workers' real/degradation paths verified; vite build passes.
6. Consolidation and continuation (2026-08-22 evening, Steps 4+5 completed).
Step 4 — Unified convergence on the caller side (confirmed, no code changes required).
- Checked all 5 digital staff execution entry points in server.js (3509/5749/5797/2358/6737) + MTClaw bridging via server.js:
- digitalStaff is loaded via server/digital-staff/loader.js, which actually returns require('../boss-scheduler/index.js') (the unified BossScheduler). Therefore, those 5 calls to digitalStaff.runStaffOnce(...) already invoke the unified scheduler.
- The old runStaffOnce in server/digital-staff/index.js (switch-case dispatching 9 staff) is no longer an execution entry point; only its utility functions like staffLog are referenced by SSE logging for long-tail usage.
- Conclusion: The client side has been unified to boss-scheduler/index.js runStaffOnce → lite-scheduler._runWorker. The three ends (web page/mini-program/Feishu/external API) converge at the same point, eliminating the need to build another scheduler.
Step 5 — Web Version Position View Tab (Implemented)
- The backend /api/digital-staff/positions already exists (server.js:4895, calling loadPositions() which consumes the local.yaml positions as the single source of truth).
- Add a third tab "Position System" to the frontend src/views/DigitalStaff.vue:
- Add a positions button to the tab-bar; create positions/positionsLoading refs + fetchPositions() (calls the above API, fetches only once) + selectStaffById() (clicking a position member jumps to the corresponding staff detail page).
- Render 16 position cards, each containing a position icon/department/member count + member chips (digital staff instances, including enabled status dot, click to navigate).
- Add staff_tab_positions + positions_* texts to the four languages (zh/en/ja/ko) in frontend/i18n.js.
- Reuse existing .status-dot/.card-bg warm gold theme styles, add new .positions-*/.agent-chip classes (scoped).
- Verification: loadPositions() actually returns 16 positions / 64 members / 0 ghosts / 0 disabled; all factory positions (Operator/Quality/Process/Scheduler/Equipment/Inventory/Finance/Purchasing/Boss/IT/Security/Chip/Market/GOAI/Procurement Closed-loop/Inspection & Repair Closed-loop) are mapped to real existing digital staff, directly eliminating the perception of "factory positions not aligned".
- Build: npm run build (vite) passes with no compilation errors.
BossAgents