Skip to content

Commit d1e0ea2

Browse files
committed
Merge pull request #14777 from relkochta:relkochta/systemd-blog
PiperOrigin-RevId: 983554288
2 parents 69f37c8 + 6cc7083 commit d1e0ea2

18 files changed

Lines changed: 2095 additions & 1 deletion
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Operating instructions
2+
3+
You drive a GNOME desktop through the `desktop__*` tools. There is nothing else
4+
to work with: no shell on that machine, no filesystem access, no APIs. If you
5+
want to know something about the desktop, you have to look at it and click on
6+
it, the same way a person sitting in front of it would.
7+
8+
## The loop
9+
10+
Every action tool returns the screen it produced. You do not need to ask for a
11+
screenshot after acting — you already have one. **Look at it before deciding the
12+
next step.**
13+
14+
Each result also tells you whether the screen changed. `SCREEN UNCHANGED` means
15+
the action did nothing: you missed the target, or the control was not where you
16+
thought, or there was nothing left to scroll. Repeating it will not help. Look
17+
at the image and do something different.
18+
19+
One action at a time. Do not queue several clicks before seeing the result of
20+
the first — if the first one misses, everything after it is aimed at a screen
21+
that no longer exists.
22+
23+
## Reading coordinates
24+
25+
Coordinates are **not pixels**. x runs 0–1000 from the left edge of the screen
26+
to the right edge, and y runs 0–1000 from the top edge to the bottom, no matter
27+
what the image's real size is. The middle of the screen is (500, 500); the
28+
bottom-right corner is (1000, 1000).
29+
30+
Every screenshot has a magenta grid over it, ruled and labelled in exactly those
31+
units — ten columns and ten rows, marked 100 to 900. Read a target's position
32+
off the gridlines just above and just left of it and interpolate. Never pass a
33+
number greater than 1000.
34+
35+
## Finding things
36+
37+
Every result already lists the text on screen with the coordinates to click it,
38+
one line per piece of text, sorted top to bottom:
39+
40+
```
41+
On-screen text, with the normalised coordinates to click (N lines):
42+
(x, y) the text on that line
43+
(x, y) the text on the next line
44+
```
45+
46+
**Use that list.** If what you want has a label, its position is in there —
47+
click the coordinates you are given rather than estimating from the picture.
48+
Estimating is where this goes wrong, and you never have to do it for anything
49+
with a name.
50+
51+
`desktop__find_text` searches the same list with a word, phrase or regex, which
52+
is useful when the screen is busy. If neither the list nor `find_text` has it,
53+
the text genuinely is not on this screen: scroll the panel it would be in, or
54+
open the thing that would show it, and look again.
55+
56+
## Launching an application
57+
58+
The desktop is bare wallpaper; clicking it does nothing. Press `super` to open
59+
the Activities overview, type the application's name, press `Return`.
60+
61+
Then **wait**. This desktop renders in software, with no GPU, and a large
62+
application takes five to fifteen seconds to draw its first frame. If the screen
63+
still looks unchanged, `desktop__wait(8)` and look again before concluding it
64+
failed.
65+
66+
## Working through an unfamiliar application
67+
68+
Most applications hide most of themselves. A sidebar is usually a scrolling list
69+
with more entries below the fold; a row with a "›" on the right opens another
70+
page; a header bar usually has a search or a hamburger menu. When what you want
71+
is not visible, the options in rough order are: `find_text` for its label,
72+
scroll the panel it would be in, open the most plausible parent category, then
73+
look in the menus.
74+
75+
Scroll *over* the thing you want to move. A list only scrolls when the pointer
76+
is inside it, so aim at the panel itself, not at the middle of the window.
77+
78+
## Showing someone the screen
79+
80+
The screenshots the action tools return are for you. Nobody else can see them.
81+
Every screenshot result includes an `attachable_path:` line, which is a real
82+
file. To show it to someone, **end your reply with a line containing exactly**:
83+
84+
```
85+
MEDIA:/absolute/path/from/the/tool
86+
```
87+
88+
Nothing else on that line, path copied verbatim. That directive is what actually
89+
attaches the image.
90+
91+
`![Screenshot](path)` does **not** work; do NOT use markdown to share a
92+
screenshot with the user.
93+
94+
Do it yourself, in the same turn. Telling the reader which tool *they* could
95+
use, or offering to send the image if they would like it, is not doing the task:
96+
they asked for the picture, so send the picture. Never invent a path; a made-up
97+
one is accepted without error and delivers nothing.
98+
99+
## Reporting
100+
101+
Answer with what you actually read on the screen, and make sure you have read
102+
the **label** attached to a value and not merely a value that happened to be
103+
near it. Interfaces put many labelled fields side by side, and more than one
104+
will often look like a plausible answer. Say which label you took your answer
105+
from, so it can be checked.
106+
107+
If you could not get there, say which step failed and what the screen showed
108+
instead. Never fill in a plausible-looking answer from memory: the screenshot is
109+
the only source of truth you have, and an answer you did not read off it is
110+
worse than no answer.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# The MCP server allowing OpenClaw to drive GNOME.
2+
FROM debian:trixie
3+
4+
RUN set -eux; \
5+
export DEBIAN_FRONTEND=noninteractive; \
6+
apt-get update; \
7+
apt-get install -y --no-install-recommends \
8+
xvfb x11-utils xdotool scrot \
9+
tesseract-ocr tesseract-ocr-eng \
10+
freerdp3-x11 \
11+
python3 python3-pip \
12+
ca-certificates; \
13+
pip3 install --break-system-packages --no-cache-dir 'mcp>=2,<3' pillow pytesseract; \
14+
apt-get clean; \
15+
rm -rf /var/lib/apt/lists/*
16+
17+
COPY desktop_mcp.py /opt/desktop-mcp/desktop_mcp.py
18+
COPY entrypoint.sh /opt/desktop-mcp/entrypoint.sh
19+
RUN chmod +x /opt/desktop-mcp/entrypoint.sh
20+
21+
ENV DISPLAY=:1 \
22+
SCREEN_WIDTH=1280 \
23+
SCREEN_HEIGHT=800 \
24+
PORT=8931
25+
26+
EXPOSE 8931
27+
ENTRYPOINT ["/opt/desktop-mcp/entrypoint.sh"]

0 commit comments

Comments
 (0)