最近、Xでこんなツイートが話題になっていました。
リモートで複数のAIエージェントやボットの「今やってること」をぱっと把握したい。
とはいえコマンドラインの真っ黒な画面では味気ない。
そんな時に役立つのが、本記事で紹介する「Star Office UI」です。
「Star Office UI」では、ピクセル絵でにぎやかな画面でAIエージェントの動作が確認できるようになります。

この記事を読むと、以下ができるようになります。
- Star Office UIをローカルで動かすための最短手順(依存関係、初期状態、起動コマンド)
- 内部構成を理解してOpenClawと連携する方法
Contents
Star Office UIとは何か?
Star Office UIは、エージェントの状態(idle, writing, syncing, errorなど)をピクセルアートの「オフィス」上で可視化するフロントエンドと、それを支える軽量バックエンドから成るプロジェクトです。コードはMITライセンスですが、アートアセットは非商用利用に制限があるためライセンスを確認してください。
公式リポジトリは GitHub – ringhyacinth/Star-Office-UI にあります。

今のところはゲーム感覚で使うものって感じかね。
でも遊び心は大事だよね。
ローカルで動かす手順
前提環境
ローカルで動かすために必要なものは次の通りです。
- Python 3.8以上(3.10を推奨)
- (任意) pip(Pythonパッケージ管理)
- (任意) 公開用にCloudflare Tunnelやnginx等の逆プロキシ
ローカルでの確認だけなら、Linux / macOS上でライブラリをインストールし、バックエンドを立ち上げてブラウザで確認するだけで十分です。
リポジトリをクローン
公式リポジトリをローカルに落とします。
git clone https://github.com/ringhyacinth/Star-Office-UI.git
cd Star-Office-UI
Python依存関係をインストール
仮想環境を作成して、ライブラリをインストールします。
python3 -m venv ./.venv
source ./.venv/bin/activate
python3 -m pip install -r backend/requirements.txt

仮想環境って面倒だけど、やっぱりやった方がいいの?

やっておくと後片付けも楽だからおすすめだよ。
初期状態ファイルをコピー
state.sample.jsonはデフォルトのエージェント状態や設定を含むので、これをコピーしてstate.jsonを作ります。
state.jsonを編集することで初期の主要エージェントやステータスを設定できます。
cp state.sample.json state.json
バックエンドを起動
cd backend
python3 app.py
起動後、ブラウザでhttp://127.0.0.1:18791を開くとUIが表示されます。
ポート番号が重複している場合、起動に失敗することがあります。
(デフォルトでは18791が設定されています)
そんな時は、backend/app.pyのapp.run内のportを別のポート番号に書き換えた後に実行してください(例:18793)。

状態を切替えて挙動確認
python3 set_state.py writing
python3 set_state.py syncing
python3 set_state.py error
python3 set_state.py idle
CLIスクリプトで状態を切り替えると、フロントエンド上のキャラクターが動きます。
(後からこれを使ってOpenClawエージェントと連動させます)
内部構成と主要APIの理解(なぜ動くかを理解する)
state.jsonと状態遷移
{
"agent": {
"name": "main",
"state": "idle",
"last_memo_file": "memory/main_2026-02-28.md"
},
"visitors": []
}
state.jsonはバックエンドが読み込む現在の「世界」。
stateの値(idle, writing, researching, executing, syncing, errorなど)に応じてフロントはアニメーションや位置を変えます。
stateを外部APIで更新するとUIに反映されます。
主要なRESTエンドポイント
バックエンドはシンプルなRESTを提供しています。代表的なエンドポイントは以下です。
- /agents — 現在のエージェント一覧を返す(GET)
- /join-agent — 新しいvisitorを追加する(POST)
- /agent-push — エージェントが状態をプッシュする(POST)
- /yesterday-memo — memory/*.mdから「昨日の小記」を返す(GET)
curl -X POST http://127.0.0.1:18791/agent-push \
-H 'Content-Type: application/json' \
-d '{"name":"lobby-bot","state":"writing","memo":"整理中です"}'
上のようにagent-pushにPOSTすると、即座にUIに反映されます。
OpenClawのステータスに応じた更新(Lifecycle Pluginによる連携)
連携方法
Start-Office-UIは、以下の実行で挙動が変わります。
そのため、これをOpenClawのエージェント開始と終了のタイミングで実行するように制御します(他に良い方法があるかもしれません)。
python3 set_state.py writing
python3 set_state.py syncing
python3 set_state.py error
python3 set_state.py idle
Lifecycle Plugin
単純にメッセージの送受信タイミングではなく、「エージェントの実行開始・終了」に正確に合わせてUIを更新したい場合、OpenClawのLifecycle Pluginが便利です。今回の実装では、エージェントの開始でwriting、終了でidle/errorに切り替えるようにしています。
- エージェントが動き出したらUIを「作業中」にしたい
- 実行終了時に「待機中」に戻したい
| タイミング | 実行内容 |
|---|---|
| before_agent_start | writingに変更 |
| agent_end | idleに変更 |
Pluginの配置と必要ファイル
以下のようにプラグインを作成します。配置先は ~/.openclaw/extensions/star-office-state-plugin/ です。
~/.openclaw/extensions/star-office-state-plugin/
├ package.json
├ openclaw.plugin.json
└ index.js
package.jsonとopenclaw.plugin.jsonはプラグインのメタ情報です。index.jsが実際のフックを受けてstateを変更する処理を呼び出します。
package.json(実装例)
{
"name": "star-office-state-plugin",
"version": "0.0.1",
"private": true,
"type": "module"
}
openclaw.plugin.json(実装例)
{
"id": "star-office-state-plugin",
"name": "Star Office State Plugin",
"description": "Set Star-Office-UI state at agent lifecycle boundaries",
"version": "0.0.1",
"kind": "lifecycle",
"main": "./index.js",
"configSchema": {
"type": "object",
"properties": {},
"additionalProperties": false
}
}
index.js(実装例)
import { execFile } from "node:child_process";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const PYTHON = "/home/kuretom/Star-Office-UI/.venv/bin/python3";
const SET_STATE_PY = "/home/kuretom/Star-Office-UI/set_state.py";
const WORKDIR = "/home/kuretom/Star-Office-UI";
async function setState(state, detail) {
try {
const { stdout, stderr } = await execFileAsync(
PYTHON,
[SET_STATE_PY, state, detail],
{
timeout: 15000,
cwd: WORKDIR,
env: {
...process.env,
VIRTUAL_ENV: "/home/kuretom/Star-Office-UI/.venv",
PATH: `/home/kuretom/Star-Office-UI/.venv/bin:${process.env.PATH ?? ""}`,
PYTHONUNBUFFERED: "1"
}
}
);
console.log(`[star-office-state] setState OK: ${state}`);
if (stdout?.trim()) {
console.log("[star-office-state] stdout:", stdout.trim());
}
if (stderr?.trim()) {
console.error("[star-office-state] stderr:", stderr.trim());
}
} catch (e) {
console.error("[star-office-state] setState failed:", e);
}
}
export default {
id: "star-office-state-plugin",
name: "Star Office State Plugin",
kind: "lifecycle",
register(api) {
console.log("[star-office-state] plugin loaded");
api.on("before_agent_start", async (_event, ctx) => {
console.log("[star-office-state] before_agent_start");
await setState("writing", "Organizing documents");
return {};
});
api.on("agent_end", async (event, ctx) => {
console.log("[star-office-state] agent_end");
if (event?.success === false) {
await setState("error", "Agent failed");
} else {
await setState("idle", "Standing by");
}
});
}
};
openclaw.jsonへの登録と動作確認
以下を~/.openclaw/openclaw.jsonに追記します。
{
"plugins": {
"allow": ["star-office-state-plugin"],
"entries": {
"star-office-state-plugin": {
"enabled": true
}
}
}
}
設定を反映したらOpenClawを再起動します。
openclaw gateway restart
動かしてみる
画面上からは、OpenClawエージェントのタスク実行に伴い、UIが変化していることが確認できます(本例では、Slackのメッセージ送信に伴い、OpenClawのエージェントが動作し、動作中は「仕事」アニメーション、動作が終われば「ソファで休憩」のアニメーションに変化しています)
ログに [star-office-state] before_agent_start 等が出ていればプラグインが動作しています。エージェントの実行をトリガーして、UI側の変化(writing→idle)を確認してください。
openclaw logs --follow
まとめ
Star Office UIは「見た目が楽しい」だけでなく、エージェント群の稼働状況を一目で把握できる実用的なダッシュボードになります。state.jsonと簡易REST APIが中心設計なので、既存の自動化ワークフローやCI/CD、OpenClawのライフサイクル連携にも自然に馴染みます。
まずはローカルで起動して画面遷移やstate.jsonの反映を確かめ、その後で以下を順に進めるのが現実的です。
- ローカルでバックエンドを起動してUIを確認する
- state.jsonの構造を把握してアセットや初期配置を調整する
- OpenClawのLifecycle Pluginで自動更新を組み込む
参考: プロジェクトとドキュメントは GitHub – ringhyacinth/Star-Office-UI を参照してください。

まずは動かしてみるのが一番だね。キャラクターたちに癒されたい…

最初は「見せたいだけ」で始めてみて、そこから誰が状態を変えているかを追えるようにすると実運用に近づくね。























ちょっと待って、それってどんなメリットがあるの?単なる可愛さ担当?