Open the file before you attach
The command finds files through the app, so attaching to a file that is not open answers no HTML Clay site is serving this file; open it first. Double-click the file, then run the command.
Agent editing
Your file is open in a tab. You type "add everything I need for a beach trip" into a box on the page and press Send. A program in your own terminal wakes up, edits the file, and the new lines appear in front of you, already saved.
Trip list
saved into the file
[wire] attached as handler to http://127.0.0.1:52341 (/Users/you/Desktop/camping.htmlclay)
That is the whole loop. This one is a demonstration; the download in the corner is the real file, and the rest of the page attaches a program to it.
No copying out of a chat window and pasting back in. No service in the middle. The program runs on your computer, as you, and the file on your disk is the only thing the two sides share.
Usually that program is an AI agent. It can just as easily be a formatter, a script you wrote, or five lines of shell. This page sets it up both ways: first with a robot that cannot fail, so you can watch the whole loop with nothing clever in it, then with an AI.
The commands below are written for a Mac and use nothing beyond what macOS already ships with. On Linux everything is identical except one line you get to skip, noted where it appears. Windows is covered at the bottom.
Save this as robot-notes.htmlclay, the same way you saved your first file: any plain text editor, plain text mode, keep the .htmlclay ending. Put it on your Desktop.
<!DOCTYPE html>
<html lang="en" autosave>
<head>
<meta charset="utf-8">
<title>Robot notes</title>
<style>
body {
font-family: system-ui, sans-serif;
max-width: 30rem;
margin: 3rem auto;
padding: 0 1rem;
}
form { display: flex; gap: 0.5rem; }
input { flex: 1; font: inherit; padding: 0.4rem 0.6rem; }
button { font: inherit; padding: 0.4rem 0.9rem; }
</style>
</head>
<body>
<h1 editable>Robot notes</h1>
<form id="ask">
<input id="said" placeholder="Ask for a change" autocomplete="off">
<button>Send</button>
</form>
<ul id="log">
<li>Lines the robot adds will show up here.</li>
</ul>
<div id="notes" editable>
<p>This part is yours. Click and type.</p>
</div>
<script src="https://clayjs.com/clay.js?plugins=sync,wire"></script>
<script>
clay.ready.then(function () {
var ask = document.getElementById("ask");
var box = document.getElementById("said");
// Built here, never typed into the file: everything you can see
// in the page is what gets saved.
var status = document.createElement("p");
status.setAttribute("clay", "no-save no-snapshot no-watch");
ask.after(status);
clay.wire.on(function (request) {
status.textContent = request.error
|| request.text
|| request.state;
});
ask.addEventListener("submit", function (event) {
event.preventDefault();
var words = box.value.trim();
if (!words) return;
box.value = "";
status.textContent = "sent";
clay.wire.send({ said: words }, { text: words });
});
});
</script>
</body>
</html>You do not have to read it. If you do, three lines are carrying the page.
wire is what gives the page a way to ask for something. sync is what makes the answer appear in the open tab without a reload.clay.wire.send is the page asking. You hand it what the person typed. Everything else on the page is an ordinary form.clay attribute on it says: show this, never save it. Build parts like that in code. If you type one into the file by hand, the first save deletes it.Double-click the file now so it is open in a tab. Press Send if you like: a moment later the status reports that nothing is attached, which is the honest answer rather than a spinner that never stops.
A robot here is just a program. Any program. HTML Clay runs it once each time the page asks for something, and three plain rules connect the two.
HTMLCLAY_WIRE_FILE.Here is a whole working robot. Save it as robot.sh, next to the page file.
#!/bin/bash
echo "working on it"
NOW=$(date "+%H:%M:%S")
LINE="<li>The robot was here at $NOW.</li>"
perl -pi -e "s|</ul>|$LINE\n </ul>|" "$HTMLCLAY_WIRE_FILE"
echo "added a line at $NOW"It prints a progress line, adds one line to the list in the file stamped with the current time, and prints that it finished. It ignores what you typed, on purpose. This first robot exists so you can watch the loop run with nothing clever inside it. The words start mattering in the next step.
Open Terminal and paste these three lines.
alias htmlclay="/Applications/HTMLClay.app/Contents/MacOS/htmlclay"
cd ~/Desktop
htmlclay wire serve robot-notes.htmlclay -- bash robot.shThe first line teaches this terminal window the htmlclay command, because on a Mac the command lives inside the app rather than on your path. It lasts until you close the window, and putting the same line in your ~/.zshrc keeps it. On Linux, skip it: htmlclay is already a command. On Windows it is htmlclay.exe, in the folder you unzipped.
The last line is the one doing the work: send requests from this file to this program. The terminal answers with one line and then waits.
[wire] attached as handler to http://127.0.0.1:52341 (/Users/you/Desktop/robot-notes.htmlclay)Your port number and your username will differ, and that is fine. Leave it running. The robot is attached to your file for exactly as long as this command runs, and not a second longer.
If it says no HTML Clay site is serving this file; open it first, the file has not been opened since HTML Clay last started. Double-click it and run the command again.
Go back to the tab, type anything into the box, and press Send. Watch the page. Within a second or two, in this order:
Press Send a few more times. One press, one run, one new line.
Three things quietly happened that are worth saying out loud. The page saved itself before asking, so the robot read exactly what you were looking at. The robot's edit went into robot-notes.htmlclay itself, so it is already saved: close the tab, open the file again, and the robot's lines are all still there. And a complete copy of the file from before the edit went into Backups, exactly as for any other save, so nothing a robot does to your file is beyond undoing.
Same loop. Swap the program.
The robot ignored your words. An AI agent is a robot that reads them.
Banana bread
Serves 4
Bake at 350°F for 55 minutes.
saved into the file
[wire] attached as handler to http://127.0.0.1:52341 (/Users/you/Desktop/banana-bread.htmlclay)
Watch the oven line: doubling a recipe is not multiplying every number, and the program left it alone. Cut down for the page, a real ask takes fifteen seconds to a minute.
This step needs one thing the rest of the page did not: an AI you can run from the terminal. The example uses Claude Code. If typing claude --version prints a version number, you are ready. If it prints command not found, the robot above has already shown you everything this page teaches, and this step will be here when you have one.
Save this as agent.sh, next to the others.
#!/bin/bash
REQUEST=$(cat)
claude --permission-mode acceptEdits -p "The file at
$HTMLCLAY_WIRE_FILE is an HTML page I have open on my screen.
This request came from inside the page: $REQUEST. Make the change
it asks for by editing that file directly. Leave everything else in
the file exactly as it is, and do not create any other files." 1>&2 &
agent=$!
while kill -0 "$agent" 2>/dev/null; do
echo "thinking"
sleep 5
done
wait "$agent"Stop the robot with Ctrl+C, because one file has one program attached at a time, and start this one instead.
htmlclay wire serve robot-notes.htmlclay -- bash agent.shNow ask for real things. "Add everything I need for a beach trip to the list." "Rewrite my notes so they are half as long." "Turn my notes into a haiku."
The rhythm is the same, only slower. The status says thinking while the agent works, and then the page changes in front of you: new list items, or your own notes rewritten in place. A small ask usually takes somewhere between fifteen seconds and a minute.
Two lines in that script are doing more than they look.
1>&2 sends the agent's own chatter to your terminal rather than the page. The page only needs to know that something is happening.Where your file goes. An AI agent reads your file and sends what it reads to its own provider, under your own account with them. That is the agent doing what you installed it to do. HTML Clay sends nothing anywhere: it starts the program you named and gets out of the way.
The agent also runs with your permissions, in the folder you started it from. acceptEdits is what lets it write without stopping to ask about every change. If you would rather approve each one, use your agent's stricter setting instead.
No document travels between the page and the program. The file is the only thing they share.
The page never talks to your program directly, and no page content travels between them. The page sends a short message. Your program edits the file with whatever tools it already has. The edit reaches the page the same way any file change does. HTML Clay calls this channel the wire, and four things about it are worth knowing even if you never look deeper.
The program runs only while your command runs. Ctrl+C, and nothing is attached to anything.
A page cannot pretend to be your program. Browsers announce themselves in ways they cannot suppress, so a web page can ask, but only a program you started yourself can answer.
A page can only reach its own file. It cannot send requests about some other file on your disk, even one open in the next tab.
Every edit is versioned. A program's change is backed up exactly like yours, even when no tab is open at the time.
Said here so you do not have to find them yourself.
The command finds files through the app, so attaching to a file that is not open answers no HTML Clay site is serving this file; open it first. Double-click the file, then run the command.
A second attach to the same file is refused while the first is running. Stop the old one with Ctrl+C first.
Every line it prints buys it more time, which is why both example scripts print while they work. An agent grinding silently on a huge request can time out. Small requests are fine.
The first time you edit the page yourself after a program has changed the file, the page reports that the file changed outside this tab. Nothing is lost, both versions are in Backups, and your save carries the program's edit forward. It reads more alarming than it is.
Changes arrive in the open page by matching elements up, so a program should edit inside elements with a stable id or data-id, like log and notes in the example file. A change inside an anonymous element may not appear until the next reload.
The app and the wire both work, but the example robots are bash scripts. Write the same three rules in PowerShell or any language you like: read standard input, print progress, edit the file named by HTMLCLAY_WIRE_FILE, exit 0. The command is the same, with the path to your htmlclay.exe in place of the alias.