Skip to content

Hackathon Submission: 'DogOps' Factory Automation Dashboard#2281

Open
seichris wants to merge 2 commits into
dimensionalOS:mainfrom
seichris:seichris/dogops-dimos-integration
Open

Hackathon Submission: 'DogOps' Factory Automation Dashboard#2281
seichris wants to merge 2 commits into
dimensionalOS:mainfrom
seichris:seichris/dogops-dimos-integration

Conversation

@seichris
Copy link
Copy Markdown

@seichris seichris commented May 28, 2026

Team: Warehouse automation

Original project repo: https://github.com/lg66lgnb-sketch/dimos-unitree-go2

Pitch

DogOps turns a Unitree Go2 into an automated site reliability operator for factories and warehouses. Instead of sending people through the floor with clipboards, teams can use DimOS to collect real-world operational data with robot-scale spatial precision, save repeatable inspection routes, and review every run from a purpose-built dashboard.

The workflow starts by gathering a floor heatmap, then annotating the virtual map with labels, assets, and no-go zones. Operators can define routes with waypoints and attach actions at each waypoint, such as capturing images for Gemini-based asset inspection, checking machine states and error readings, or scanning QR codes and AprilTags to confirm object identity and position. Routes can be run immediately or scheduled for repeated execution, like a real-world cron job for physical operations.

Each run stores its route, events, observations, images, and analysis outputs so warehouse teams can audit what changed, compare runs over time, and turn robot inspections into operational records.

This PR also reflects a broader product direction: custom industrial apps should be a primary interface for DimOS. DogOps packages the dashboard, route engine, examples, tests, and Go2 blueprint as importable DimOS modules so this app can run inside the full DimOS checkout and serve as a template for similar applications.


Watch the demo video at https://www.youtube.com/watch?v=iM8s6TYot9c

warehouse.dimos-go2.demo.video.mp4

@seichris seichris marked this pull request as ready for review May 28, 2026 14:33
@seichris seichris changed the title Add DogOps experimental Go2 dashboard Hackathon Submission: Add DogOps experimental Go2 dashboard May 28, 2026
@seichris seichris changed the title Hackathon Submission: Add DogOps experimental Go2 dashboard Hackathon Submission: Add DogOps Factory Automation dashboard May 28, 2026
@seichris
Copy link
Copy Markdown
Author

seichris commented May 28, 2026

Watch our video at: https://www.youtube.com/watch?v=iM8s6TYot9c


warehouse.dimos-go2.demo.video.mp4

@seichris seichris changed the title Hackathon Submission: Add DogOps Factory Automation dashboard Hackathon Submission: 'DogOps' Factory Automation Dashboard May 28, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 28, 2026

Greptile Summary

This PR adds the DogOps factory-automation dashboard as a new experimental package under dimos/experimental/dogops, wiring it into the Go2 robot stack and fixing an MCP startup deadlock by replacing remote get_skills() RPC calls with local class inspection.

  • New dogops package (~19k lines): dashboard HTTP server, route executor, mission engine, skills container, Gemini vision, QR-cargo tracking, map authoring, and a full test suite.
  • MCP fix (mcp_server.py): _module_class_skills derives skill schemas locally from actor_class instead of round-tripping to each module at startup, avoiding the deadlock described in the PR notes.
  • Blueprint registration (all_blueprints.py): Adds dogops-go2-stack and unitree-go2-dogops entries, but dogops-go2-stack references a non-existent symbol (dogops_go2_stack) — the exported name in blueprints.py is unitree_go2_dogops.

Confidence Score: 3/5

Not safe to merge as-is: the dogops-go2-stack blueprint entry is outright broken (wrong symbol name), and two dashboard endpoints allow unauthenticated state mutation reachable via CSRF from the local browser.

The broken symbol in all_blueprints.py means dimos run dogops-go2-stack will fail immediately on any deployment. The two unguarded POST endpoints in the dashboard let any page loaded in the operator's browser silently flip work-order state and write arbitrary data to disk — without the token check that guards every other mutating route in the same file. Both issues are straightforward to fix but need to land before the PR is merged.

dimos/robot/all_blueprints.py (wrong symbol for dogops-go2-stack) and dimos/experimental/dogops/dashboard.py (unguarded /api/work_orders and /api/operator/event endpoints)

Security Review

  • Missing authorization on two mutating POST endpoints (dashboard.py): POST /api/work_orders/{id}/ready_to_verify and POST /api/operator/event carry no loopback, origin, or token check. Every other mutating route in the same handler requires _authorize_map_authoring_write() or _authorize_robot_control(). A malicious page open in the user's browser can CSRF-POST to http://127.0.0.1:8765/api/work_orders/WO-001/ready_to_verify, flipping work-order state and rewriting state.json/report.md. The _record_operator_event path additionally writes an arbitrary attacker-controlled JSON payload directly to disk with no schema validation.

Important Files Changed

Filename Overview
dimos/agents/mcp/mcp_server.py Replaces remote get_skills() RPC with local class inspection (_module_class_skills) to avoid startup deadlocks; SkillInfo import moved to runtime. The dir()-based skill discovery may expose inherited skills from base classes.
dimos/robot/all_blueprints.py Registers dogops-go2-stack and unitree-go2-dogops blueprints plus two new modules. The dogops-go2-stack entry references a non-existent symbol dogops_go2_stack — should be unitree_go2_dogops.
dimos/experimental/dogops/dashboard.py Large new dashboard HTTP server (~2400 lines). POST /api/work_orders/{id}/ready_to_verify and POST /api/operator/event are the only mutating endpoints that lack any authorization guard, enabling CSRF-style mutations from any browser tab.
dimos/experimental/dogops/blueprints.py Defines unitree_go2_dogops blueprint but calls the factory function at module-import time, triggering heavy imports during blueprint listing; exports unitree_go2_dogops, not dogops_go2_stack.
dimos/experimental/dogops/skills.py DogOpsSkillContainer exposes robot navigation, scanning, and reporting skills via MCP with robust fallbacks for full DimOS vs. standalone checkout.
dimos/experimental/dogops/route_executor.py Waypoint-by-waypoint route execution with retry, progress timeout, stop-on-request, and dry-run support; locks route_execution.json to prevent concurrent runs.
dimos/robot/unitree/go2/blueprints/agentic/unitree_go2_dogops.py Thin blueprint wiring the Go2 hardware stack to DogOps modules; uses try/except fallback stubs so the file compiles without the full DimOS SDK installed.
dimos/experimental/dogops/store.py JSON/JSONL run store for offline simulation; write operations are straightforward but lack concurrency locks (acceptable for the current single-threaded offline use case).
dimos/experimental/dogops/models.py Pydantic data models for the DogOps domain (zones, assets, incidents, nav events, etc.); well-structured with explicit enums and field defaults.

Sequence Diagram

sequenceDiagram
    participant Browser
    participant DashboardServer as DogOpsDashboardServer
    participant MCPServer as McpServer
    participant DogOpsSkillContainer
    participant DogOpsStore

    Note over Browser,DogOpsStore: Normal robot-control flow (authenticated)
    Browser->>DashboardServer: POST /api/robot/jog + X-DogOps-Control-Token
    DashboardServer->>DashboardServer: _authorize_robot_control() ok
    DashboardServer->>MCPServer: HTTP call to follow_route / go_to
    MCPServer->>DogOpsSkillContainer: RPC via RpcCall
    DogOpsSkillContainer->>DogOpsStore: read/write state.json

    Note over Browser,DashboardServer: Unguarded mutation - no auth
    Browser->>DashboardServer: POST /api/work_orders/WO-001/ready_to_verify
    DashboardServer->>DogOpsStore: load_existing, update_work_order, write_state, write_report

    Note over MCPServer,DogOpsSkillContainer: Startup skill discovery new approach
    MCPServer->>MCPServer: on_system_modules(modules)
    MCPServer->>MCPServer: _module_class_skills inspects actor_class locally
    MCPServer->>DogOpsSkillContainer: RPC at call time only
Loading

Reviews (1): Last reviewed commit: "Default DogOps live routes to direct dri..." | Re-trigger Greptile

"demo-osm": "dimos.mapping.osm.demo_osm:demo_osm",
"demo-skill": "dimos.agents.skills.demo_skill:demo_skill",
"desk-marker-tf": "dimos.perception.fiducial.blueprints.desk_marker_tf:desk_marker_tf",
"dogops-go2-stack": "dimos.experimental.dogops.blueprints:dogops_go2_stack",
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.

P1 Broken blueprint symbol — dogops_go2_stack is never defined

dimos/experimental/dogops/blueprints.py exports unitree_go2_dogops (line 48), not dogops_go2_stack. Anyone who runs dimos run dogops-go2-stack or loads this entry in the registry will get an ImportError / AttributeError at the module-import boundary. The "unitree-go2-dogops" entry below (which correctly points to unitree_go2_dogops.py) covers the same blueprint — so either the dogops-go2-stack entry needs to point to the right symbol (unitree_go2_dogops) or a dogops_go2_stack alias needs to be added to blueprints.py.

Suggested change
"dogops-go2-stack": "dimos.experimental.dogops.blueprints:dogops_go2_stack",
"dogops-go2-stack": "dimos.experimental.dogops.blueprints:unitree_go2_dogops",

Comment on lines +304 to +310
def do_POST(self) -> None:
path = urlparse(self.path).path
if path.startswith("/api/work_orders/") and path.endswith("/ready_to_verify"):
work_order_id = path.split("/")[3]
self._mark_work_order_ready(work_order_id)
elif path == "/api/operator/event":
self._record_operator_event()
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.

P1 security Unauthenticated state-mutation endpoints

POST /api/work_orders/{id}/ready_to_verify and POST /api/operator/event are the only two mutating POST routes that skip every authorization check. Every other mutating POST in this handler (/api/qr/events, /api/map/…, /api/robot/…) calls _authorize_map_authoring_write() or _authorize_robot_control() first. Without the loopback + origin + token checks, any page loaded in the browser can send a CSRF-style fetch to http://127.0.0.1:8765/api/work_orders/WO-001/ready_to_verify — the mutation completes even though the response is blocked by the browser's same-origin policy. _mark_work_order_ready also re-writes state.json and report.md, so the impact is data corruption rather than just a log entry.

Comment on lines +360 to +378
for name in dir(actor_class):
attr = getattr(actor_class, name, None)
if not callable(attr) or not hasattr(attr, "__skill__"):
continue
schema = tool(attr).args_schema.model_json_schema()
properties = schema.get("properties")
if isinstance(properties, dict):
properties.pop("self", None)
required = schema.get("required")
if isinstance(required, list) and "self" in required:
schema["required"] = [item for item in required if item != "self"]
skills.append(
SkillInfo(
class_name=actor_class.__name__,
func_name=name,
args_schema=json.dumps(schema),
)
)
return skills
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.

P2 dir() iteration may expose inherited / unrelated __skill__-marked attributes

dir(actor_class) walks the entire MRO — including all Module base-class methods and any mixin that happens to carry __skill__. If a base class ever gains a @skill-decorated method, it will appear as a skill for every deployed module rather than just the one that defines it, inflating the tool list and potentially registering a duplicate func_name key in app.state.rpc_calls. Consider restricting to vars(actor_class) to capture only the methods defined directly on the concrete class.

).global_config(n_workers=12, robot_model="unitree_go2")


unitree_go2_dogops = build_unitree_go2_dogops_blueprint()
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.

P2 Module-level blueprint construction triggers imports at list time

build_unitree_go2_dogops_blueprint() is called at module-import time, which means importing dimos.experimental.dogops.blueprints (e.g. when dimos list walks all_blueprints) immediately executes all the try import blocks, including dimos.agents.mcp.mcp_server and dimos.core.coordination.blueprints. This is the same pattern that the MCP change in this PR is trying to fix for deadlocks. The preferred DimOS pattern is a lazy factory function.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@lg66lgnb-sketch
Copy link
Copy Markdown

Demo video: https://youtu.be/iM8s6TYot9c

@leshy leshy added the hackaton label May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants