Internal guide

Publishing a static site on piku

A walk through what actually happens when a naive agent picks up the publish-static-site skill, writes a page by hand, and pushes it live. No framework, no build step, no container image - just files on disk.

1. The whole idea in one sentence

Piku serves the directory you push, straight off disk. A Procfile reading static: . tells it there is no app process to run, so it starts nothing, builds nothing and pulls no image. The publish is a git push, and the first push costs exactly what the last one costs.

Why there is no build step

A static site has nothing to compile. The HTML you write is the HTML that is served. So the page is authored directly - no Markdown conversion, no generator script, no dependency to install. If you find yourself writing a tool to produce the page, you have already left the lane.

2. What the skill hands you

Read the skill first. It is short and it is the whole specification. For a site called guide on port 8005 it describes a directory that looks like this, and nothing else:

FileContentsWhy
Procfile static: . Declares the static lane. No app process, no healthcheck target, no restart loop.
ENV PORT=8005 Pins the port. Pick a free one on the instance rather than trusting a registry.
index.html The page itself. Served for /. This is the deliverable.
style.css The stylesheet. Linked by hand from the HTML. Piku serves it next to the page; it is not bundled.

The styling is ordinary, hand-written CSS linked from the <head>. Nothing about the static lane requires a framework, and adding one means the build has moved out of scope.

3. The publish sequence

Four commands, run in the site directory:

git init -q -b main && git add -A && git commit -m "guide: static site"
git remote add piku piku@piku:guide
git push piku HEAD:main

git push over SSH to the instance is the entire deployment. There is no image to pull, no dependency resolution, no compile step, and no health gate to wait on.

Update, afterwards

The same three commands minus init and remote add. The site is live on the next push. There is no restart to schedule, because there is no process to restart.

4. Checking that it worked

One HTTP request against the instance and the pinned port:

ssh piku@piku 'curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8005/'

A 200 means the directory was picked up, the port was free, and the page is being served. Any other code is a stop - not a second try.

5. What the skill deliberately does not do

It does not pick a URL.
Exposure is a separate layer with a separate skill. The static lane ends at http://piku:<port> inside the tailnet.
It does not expose anything itself.
A human runs ivps expose-service cloudai:piku <name> <port> to get a tailnet link. The agent never wires tailscale serve inside the container.
It does not teardown.
Removal is ssh piku@piku 'destroy <name>', and it needs the human's consent first. A probe publishes and leaves it standing.
It does not add fallbacks.
No retries, no second remote, no alternate lane when a push fails. A failure is reported with its exact output so the skill can be judged.

6. The shape of a successful probe

  1. Load the skill and read it as the specification.
  2. Write the files directly: Procfile, ENV, index.html, style.css.
  3. Commit once, add the remote once, push once.
  4. One HTTP check, expecting 200.
  5. Report the URL and hand the human the one ivps command for a tailnet link.

If any single step misbehaves - an error, a non-200, a need to guess something the skill left open - the run stops there. one attempt The trace of what did happen is worth more than a site that eventually came up after three retries.