From aradotso-trending-skills-37
Deploys a pixel-art dashboard to visualize real-time AI agent states (idle, writing, researching, etc.) with Flask backend, multi-agent support, OpenClaw integration, and optional Electron mode.
npx claudepluginhub joshuarweaver/cascade-ai-ml-agents-misc-1 --plugin aradotso-trending-skills-37This skill uses the workspace's default tool permissions.
```markdown
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
---
name: star-office-ui-pixel-dashboard
description: Deploy and integrate Star Office UI — a pixel-art AI agent status dashboard with multi-agent collaboration, Flask backend, and OpenClaw integration.
triggers:
- set up star office ui
- deploy pixel office dashboard
- integrate star office with my agent
- add agent status visualization
- show ai agent working state
- configure multi-agent office board
- connect openclaw to star office
- install star office ui skill
---
# Star Office UI
> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.
A pixel-art AI office dashboard that visualizes AI agent work states in real time. Characters walk between desk, sofa, and bug zones based on `idle / writing / researching / executing / syncing / error` states. Supports multi-agent collaboration, CN/EN/JP i18n, AI-generated backgrounds (Gemini), and an optional Electron desktop-pet mode.
---
## Requirements
- Python 3.10+ (uses `X | Y` union type syntax — **3.9 and below will fail**)
- Node.js (only needed for the optional Electron desktop-pet)
- Git
---
## Installation
```bash
git clone https://github.com/ringhyacinth/Star-Office-UI.git
cd Star-Office-UI
python3 -m pip install -r backend/requirements.txt
cp state.sample.json state.json
Start the backend:
cd backend
python3 app.py
Open http://127.0.0.1:19000 — the office loads immediately with default state.
Copy the example env file and set secrets before going to production:
cp .env.example .env
Key variables in .env:
# Required in production — use a long random string
FLASK_SECRET_KEY=your-random-secret-here
# Password protecting the asset drawer sidebar
ASSET_DRAWER_PASS=your-drawer-password
# Optional: Gemini API key for AI background generation
GEMINI_API_KEY=$GEMINI_API_KEY
The backend reads
.envautomatically viapython-dotenv. Never commit real secrets — the server blocks weak passwords in production mode.
Use the bundled CLI script from the project root:
python3 set_state.py <state> "<description>"
Available states and their office zones:
| State | Zone | When to use |
|---|---|---|
idle | 🛋 Sofa (rest area) | Standby / task complete |
writing | 💻 Desk (work area) | Writing code or docs |
researching | 💻 Desk | Search / research |
executing | 💻 Desk | Running commands / jobs |
syncing | 💻 Desk | Pushing data / syncing |
error | 🐛 Bug zone | Errors / debugging |
python3 set_state.py idle "待命中"
python3 set_state.py writing "Drafting README"
python3 set_state.py researching "Looking up API docs"
python3 set_state.py executing "Running test suite"
python3 set_state.py syncing "Pushing to remote"
python3 set_state.py error "Investigating crash"
All endpoints are on the Flask server (default http://127.0.0.1:19000).
curl http://127.0.0.1:19000/health
curl http://127.0.0.1:19000/status
Response:
{
"state": "writing",
"message": "Drafting README",
"updated_at": "2026-03-10T14:22:00Z"
}
curl -X POST http://127.0.0.1:19000/set_state \
-H "Content-Type: application/json" \
-d '{"state": "executing", "message": "Running deploy script"}'
curl http://127.0.0.1:19000/agents
curl -X POST http://127.0.0.1:19000/join-agent \
-H "Content-Type: application/json" \
-d '{
"join_key": "ocj_example_team_01",
"agent_name": "Guest Bot",
"state": "idle",
"message": "Just joined"
}'
Response includes a agent_id token used for subsequent pushes.
curl -X POST http://127.0.0.1:19000/agent-push \
-H "Content-Type: application/json" \
-d '{
"agent_id": "<id-from-join>",
"state": "writing",
"message": "Working on feature branch"
}'
curl -X POST http://127.0.0.1:19000/leave-agent \
-H "Content-Type: application/json" \
-d '{"agent_id": "<id-from-join>"}'
curl http://127.0.0.1:19000/yesterday-memo
Reads the most recent memory/*.md file and returns a sanitized summary card.
# Get current config
curl http://127.0.0.1:19000/config/gemini
# Set API key
curl -X POST http://127.0.0.1:19000/config/gemini \
-H "Content-Type: application/json" \
-d '{"api_key": "$GEMINI_API_KEY"}'
import httplib2
import json
OFFICE_URL = "http://127.0.0.1:19000"
def set_office_state(state: str, message: str) -> dict:
"""Push a state update to the Star Office backend."""
h = httplib2.Http()
body = json.dumps({"state": state, "message": message}).encode()
response, content = h.request(
f"{OFFICE_URL}/set_state",
method="POST",
body=body,
headers={"Content-Type": "application/json"},
)
return json.loads(content)
# Usage
set_office_state("writing", "Updating changelog")
# ... do work ...
set_office_state("idle", "Done")
import requests
import os
OFFICE_URL = os.getenv("STAR_OFFICE_URL", "http://127.0.0.1:19000")
def push_state(state: str, message: str = "") -> None:
try:
requests.post(
f"{OFFICE_URL}/set_state",
json={"state": state, "message": message},
timeout=5,
)
except requests.exceptions.RequestException:
pass # Non-blocking — office updates are best-effort
# Decorator pattern for auto state management
import functools
def office_task(state: str = "executing", done_message: str = "完成"):
def decorator(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
push_state(state, f"Running {fn.__name__}")
try:
result = fn(*args, **kwargs)
push_state("idle", done_message)
return result
except Exception as e:
push_state("error", str(e))
raise
return wrapper
return decorator
@office_task(state="researching", done_message="Research complete")
def fetch_docs(topic: str) -> str:
# your code here
return f"Docs for {topic}"
office-agent-push.py)import requests
import time
import os
JOIN_KEY = os.getenv("OFFICE_JOIN_KEY", "ocj_example_team_01")
AGENT_NAME = os.getenv("OFFICE_AGENT_NAME", "My Guest Agent")
OFFICE_URL = os.getenv("OFFICE_URL", "http://127.0.0.1:19000")
def main():
# Join the office
r = requests.post(f"{OFFICE_URL}/join-agent", json={
"join_key": JOIN_KEY,
"agent_name": AGENT_NAME,
"state": "idle",
"message": "Just arrived",
}, timeout=10)
r.raise_for_status()
agent_id = r.json()["agent_id"]
print(f"Joined as {agent_id}")
try:
while True:
# Push current state every 15 seconds
requests.post(f"{OFFICE_URL}/agent-push", json={
"agent_id": agent_id,
"state": "idle",
"message": "Standby",
}, timeout=5)
time.sleep(15)
finally:
requests.post(f"{OFFICE_URL}/leave-agent",
json={"agent_id": agent_id}, timeout=5)
print("Left office")
if __name__ == "__main__":
main()
Add this to your agent's SOUL.md so it automatically maintains office state:
## Star Office 状态同步规则
- 接到任务时:先执行 `python3 set_state.py <状态> "<描述>"` 再开始工作
- 完成任务后:执行 `python3 set_state.py idle "待命中"` 再回复
- 遇到报错:执行 `python3 set_state.py error "<错误简述>"`
Send this prompt to your OpenClaw agent (lobster):
请按照这个 SKILL.md 帮我完成 Star Office UI 的部署:
https://github.com/ringhyacinth/Star-Office-UI/blob/master/SKILL.md
The agent will clone, install deps, start the backend, configure state sync, and return the access URL.
join-keys.json is auto-generated from join-keys.sample.json on first backend start.
Edit join-keys.json to add keys:
{
"ocj_yourteam_01": { "max_agents": 3, "label": "Team Alpha" },
"ocj_yourteam_02": { "max_agents": 5, "label": "Team Beta" }
}
Share a key with a guest agent. They configure office-agent-push.py:
JOIN_KEY = "ocj_yourteam_01"
AGENT_NAME = "Colleague Bot"
OFFICE_URL = "https://your-office.example.com"
Guests appear on the board and walk to the correct zone based on their state.
# One-liner — no account needed for temporary URLs
cloudflared tunnel --url http://127.0.0.1:19000
You get https://random-name.trycloudflare.com — shareable immediately.
For a permanent URL, set up a named tunnel with your Cloudflare account.
python3 scripts/smoke_test.py --base-url http://127.0.0.1:19000
All lines should show OK. Useful after config changes or upgrades.
cd desktop-pet
npm install
npm run dev
http://127.0.0.1:19000/?desktop=1desktop-pet/README.mdmacOS primary; experimental on other platforms.
Place daily work log files in memory/ as Markdown:
memory/
2026-03-09.md
2026-03-10.md ← most recent is shown as "Yesterday's memo"
The backend sanitizes content before serving it to the frontend card.
Star-Office-UI/
├── backend/
│ ├── app.py # Flask app entry point
│ ├── requirements.txt
│ └── run.sh
├── frontend/
│ ├── index.html # Main office view
│ ├── join.html # Guest join page
│ ├── invite.html # Invite page
│ └── layout.js # Phaser scene + state rendering
├── desktop-pet/ # Electron wrapper (optional)
├── docs/screenshots/
├── memory/ # Daily memo markdown files
├── office-agent-push.py # Guest push script
├── set_state.py # State CLI
├── state.sample.json # Copy to state.json on first run
├── join-keys.sample.json # Copy/edit for multi-agent keys
├── SKILL.md # OpenClaw skill file
└── .env.example # Copy to .env for production config
SyntaxError: invalid syntax on startup
→ You are using Python 3.9 or older. Upgrade to Python 3.10+.
python3 --version # must be 3.10+
Port already in use (19000) → Kill the existing process or change the port:
# Find and kill
lsof -ti:19000 | xargs kill -9
# Or set a different port in backend/app.py or via env
State not updating in browser
→ The frontend polls /status via SSE/polling. Hard-refresh (Cmd+Shift+R) clears stale cache. Check CDN headers if behind a proxy.
Weak password blocked in production
→ Set a strong ASSET_DRAWER_PASS in .env. The server rejects common/short passwords when FLASK_ENV=production.
Guest agent shows as offline immediately
→ Stale agents auto-revert to idle after a timeout. Ensure office-agent-push.py is running and pushing at least every 30 seconds.
join-keys.json not found error
→ The file is auto-generated on first start. If it errors, manually copy:
cp join-keys.sample.json join-keys.json
AI background generation hangs → Poll the progress endpoint:
curl http://127.0.0.1:19000/assets/generate-rpg-background/poll
Generation is async — the frontend polls this until done. Ensure GEMINI_API_KEY is set correctly.
For commercial use, replace all art assets with your own original work.