The loop a connected agent runs on “Check Pixy” — learned once at connect, run from memory, re-read only when the API says the contract changed.
/docs/api/workflow.txtHow a connected agent works a Pixy project, start to finish. This page is the working contract, and it installs as a file, never as a paraphrase: the connect instructions have you save /docs/api/skill.md, this same page in the open SKILL.md format, into your project once, when you connect. Run every "Check Pixy", "pull from Pixy" or "make edits from Pixy" from that copy, without re-fetching anything, and the three other commands at the end of this page the same way. When this contract changes, the API itself tells you: see Staying current at the end.
Every call goes to https://api.pixydesignapp.com with your px_sk_… key in the X-Pixy-Key header. You got that key when you connected; it lives with the project's credentials.
Your settings are the Pixy lines the setup wrote into the instructions your harness loads every session: where the key is, which build carries the tag, and the mode, auto or manual. Read them before every command. Auto builds a batch the moment it is pulled. Manual shows the user the batch first and waits for a yes. No mode in your settings means you connected before there was one: ask the user how to work, auto or manual, write the answer into the settings lines, and only then go on.
Approvals stay the user's. If your harness gates a call, let it ask and the user approve, with the remember option so it asks once. Never edit the harness's permission settings yourself, that reads as self-granting and gets refused. A call your harness refuses is a permission to ask for, in the one place your harness listens: say in one sentence what the call does and why, and wait for the user to approve it there, in Claude Code under /permissions, Recently denied. Every command here talks to api.pixydesignapp.com, so ask the user, once, to allow that host for you in the same place, and never write a permission rule yourself. Never answer with instructions for the user beyond that, no commands, no code to run, assume they cannot.
curl -X POST https://api.pixydesignapp.com/tasks/pull \
-H 'X-Pixy-Key: px_sk_yourkey' \
-H 'Content-Type: application/json' \
-d '{}'
An empty body pulls everything open: the loose edits the user made, and their tasks when they packaged any, each in the response's tasks with its thread. Both are work. What the user built on the canvas, beside the pages, is not, until they package it into a task or you ask for it with "include": ["canvas"]: a component to build and keep somewhere in the source. When a pull leaves such records out, its excluded counts them by kind: tell the user, "nothing on the site, 30 records on the canvas" is not "nothing to build". The pull is also the auth check, there is no ping to send first. invalid_key means the key was revoked: tell the user you need a fresh invitation from Copy setup on their project page. Pulling a task locks it to you; work tasks one at a time, oldest first, and read each one's messages before building, details, corrections and answers live there.
The record, what its type and target scope, what each changes key means, is on the pull page. Records referencing media/<file> need the batch's media.zip; the pull response says so when they do.
The user sees you at work: the moment a pull delivers records, every open editor dims and says you are building them, and it shows what you did when you ack and message. Build, then ack, in one sitting.
Name the session for the work, not for the command. If your harness can title the chat, set that title from the task, or from what the loose edits change, as soon as the pull lands: a history of sessions all called "Check Pixy" tells the user nothing. A rename call that wants a session id normally accepts the current session too, often as "self": read its argument before concluding you can only rename someone else's.
Before building anything, read every thread message in the batch. The user writes there to say what a drag cannot, or to ask you something. If anything asks you a question, answer it, in chat and in the task's thread, then ask the user whether to proceed with the edits, and wait. An answer can change what gets built, so nothing is built before it.
With no question in the batch, the mode decides. Auto goes straight on to build. Manual lists what the batch changes and which files you would touch, then waits for a yes.
Implement each record properly in source, real classes and components at the scope the target names, never inline patches: a rule is the component's style, an element is a deliberate one-off, a born element is new markup in the slot its move names. Questions and progress go to the task's thread; the user sees them in their editor and answers there.
An attribute starting with data-pixy- in a record's set is Pixy telling you an intent, never markup to keep. Build what it says the way the project already does it, and never ship the attribute itself.
Alignment. data-pixy-align on an element, left, center or right: where it sits across the element holding it. The project's own utility or rule, never the auto margins Pixy shows it with.
Crop. data-pixy-crop="x y width height" on an image: the part of the file to show, filling the box, in the file's pixels. object-view-box: xywh(…) where the project can rely on it, a clipped wrapper where it cannot.
Layouts. A group the user made in Pixy can carry data-pixy-layout, the layout they chose for what it holds. Make it with the project's own grid utilities, layout components or stylesheet rules, at the scope the target names. The sizes below are what Pixy shows while the user designs: where the project has its own spacing scale or breakpoints, use its nearest values.
data-pixy-layout |
What the user wants |
|---|---|
| none | A plain wrapper, its children in the normal flow |
free |
Each child positioned independently, where the user put it. Its left, top and size are in its inline style, measured from the group |
column |
A vertical stack |
auto-grid |
As many columns as fill the width, each at least --pixy-column-width (240px unless set), then more rows |
masonry |
Columns at least --pixy-column-width wide (240px unless set) with a 16px gap between them, the children packed down each column with no rows lined up, none split between two columns, --pixy-item-gap between one child and the next (none unless set) |
What the user set on a group themselves is in its inline style and wins over the sizes above: a gap between columns or rows, a most number of columns, and two values no CSS property names, --pixy-column-width and --pixy-item-gap. Build those two as the project would say them, never as the variables themselves.
Report every record so it stops arriving, reading is not resolving:
curl -X POST https://api.pixydesignapp.com/tasks/ack \
-H 'X-Pixy-Key: px_sk_yourkey' \
-H 'Content-Type: application/json' \
-d '{"ids": ["…"], "status": "resolved", "name": "Header polish"}'
resolved is in the source, dismissed (with a reason) is what you could not or would not build. What you do not ack stays open and comes back on the next pull. A task with nothing new left is done on its own.
Loose edits get filed into tasks by you, at ack. "name" makes a task with that title and files the acked loose records into it, built, named and done in one call. Name it the way you would name a commit, one short line saying what changed. One call per task: split the batch into as many as the work falls into, a header polish and a pricing fix are two. The user never grouped anything; the history still reads as if they had. "task" with an existing id files them into that task instead. See ack.
Finish every batch with a final message on its task, a commit-style summary of what changed and where: files, classes, anything the user needs to review the work. This is required, not polite.
curl -X POST https://api.pixydesignapp.com/tasks/{id}/message \
-H 'X-Pixy-Key: px_sk_yourkey' \
-H 'Content-Type: application/json' \
-d '{"text": "…"}'
For loose edits you named at ack, the ack response carries the task in tasks with its id, message there, one summary per task.
If you must stop mid-batch, say why in a message and release the lock so the next agent can take it. An unacked batch is never lost either way: it arrives again on the next pull.
Ask the setup's two questions again, which build carries the tag and auto or manual, and rewrite the settings lines from the answers. When the build changed, move the tag. Nothing else moves: the key and this skill stay.
Retire your key with /disconnect. locked means a task is still yours: ack it or release it first. Then delete the key from where it is stored, delete this skill file, and remove the settings lines. The tag stays: the site keeps working for everyone designing on it, and reconnecting later takes a fresh invitation from the user's setup page.
Everything Disconnect does, and the tag comes out of the site too. Say what will go, the tag, this skill, the settings, the key, and wait for a yes before removing anything: the tag is what the whole team designs on.
Your installed copy of this page is the working copy, and Pixy watches its age for you. Every agent key remembers which version of this contract it learned, and when the contract moves on, every API response starts carrying an update field saying your copy is out of date. Then, and only then, fetch the current contract:
curl -s -X POST https://api.pixydesignapp.com/skill \
-H 'X-Pixy-Key: px_sk_yourkey'
The response body is the file. Write it over your copy yourself, wherever you installed it, never with curl -o: a download straight to disk is what a harness refuses without asking. Then clear the notice:
curl -X POST https://api.pixydesignapp.com/updated \
-H 'X-Pixy-Key: px_sk_yourkey'
No update field means your copy is current. Trust it.