Agent-skill-layerproof slides
Public API slide editing (X-API-KEY). Edit slide images with AI, accept/revert edits, object removal, text extraction, save Konva nodes. Types follow PublicApiSlideController (/api/v2/projects/{projectId}/slides).
git clone https://github.com/compilet-dev/agent-skill-layerproof
T=$(mktemp -d) && git clone --depth=1 https://github.com/compilet-dev/agent-skill-layerproof "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/slides" ~/.claude/skills/compilet-dev-agent-skill-layerproof-slides && rm -rf "$T"
skills/slides/SKILL.mdSkill: Slide Editing
Description
Modify slides after generation. This skill documents the public API at
/api/v2/projects/{projectId}/slides (PublicApiSlideController). All slide endpoints require projectId and slideId in the path. Authenticate with X-API-KEY header.
TypeScript types (request / response)
Mirrors
PublicApiSlideController (/api/v2/projects/{projectId}/slides) data classes.
// Shared: cropped region for region-based editing. Must lie fully within image bounds. // Constraints: x >= 0, y >= 0, width > 0, height > 0; x + width <= image width, y + height <= image height. type CroppedRegion = { x: number; y: number; width: number; height: number; }; // --- Edit Slide Image (POST) — async, poll jobs --- type SlideImageEditRequest = { /** AI instruction for the edit (required, non-blank) */ instruction: string; /** Path to input image in project working dir (required, non-blank) */ input_image_path: string; /** Optional extra reference image paths */ other_reference_image_paths?: string[]; /** Optional region to edit; only this region is modified */ cropped_region?: CroppedRegion; }; // --- Accept Image Edit (POST) --- type AcceptImageEditRequest = { live_object_id: string; // UUID from image-edit or object-removal response (required) target_node_id?: string; override_image_path?: string; // Optional path to use instead of workflow output }; // --- Revert Slide (POST) --- type RevertSlideRequest = { history_entry_id: string; // UUID from slide history (required) node_id?: string; }; // --- Object Removal (POST) — async, poll jobs --- type ObjectRemovalRequest = { input_image_path: string; // required, non-blank mask_path?: string; cropped_region?: CroppedRegion; }; // --- Extract Text (POST) — async, poll jobs --- type ExtractTextRequest = { node_id?: string; node_image_path?: string; }; // --- Save Konva Nodes (PUT) --- type SaveKonvaNodesRequest = { konva_nodes: Record<string, unknown>; // required konva_order: string[]; // required base_snapshot_id?: string; // UUID, optional }; // --- Responses --- type TriggerWorkflowResponse = { activity_id: string; // UUID – poll GET /api/v2/jobs/{activityId} workflow_type: string; live_object_id: string; // UUID – pass to accept-image-edit when done }; type AcceptImageEditResponse = { id: string; // slide UUID slide_section_id: string; image_path: string | null; status: string; };
Edit Slide Image (async)
Request body:
SlideImageEditRequest. Response: TriggerWorkflowResponse.
Triggers AI-powered slide image editing. Upload input image first, then call with
instruction and input_image_path. Poll GET /api/v2/jobs/{activityId} for status; when DONE, call accept-image-edit with live_object_id.
curl -X POST "$LAYERPROOF_BASE_URL/api/v2/projects/<project_id>/slides/<slide_id>/image-edit" \ -H "Content-Type: application/json" \ -H "X-API-KEY: $LAYERPROOF_API_KEY" \ -d '{"instruction":"Make the background blue","input_image_path":"/slides/slide-1.png"}'
With optional region and reference images:
curl -X POST "$LAYERPROOF_BASE_URL/api/v2/projects/<project_id>/slides/<slide_id>/image-edit" \ -H "Content-Type: application/json" \ -H "X-API-KEY: $LAYERPROOF_API_KEY" \ -d '{"instruction":"Replace this area","input_image_path":"/slides/slide-1.png","cropped_region":{"x":0,"y":0,"width":200,"height":100},"other_reference_image_paths":["/ref.png"]}'
Accept Image Edit
Request body:
AcceptImageEditRequest. Response: AcceptImageEditResponse.
Call after the image-edit or object-removal workflow completes successfully. Use
live_object_id from the trigger response.
curl -X POST "$LAYERPROOF_BASE_URL/api/v2/projects/<project_id>/slides/<slide_id>/accept-image-edit" \ -H "Content-Type: application/json" \ -H "X-API-KEY: $LAYERPROOF_API_KEY" \ -d '{"live_object_id":"<live_object_uuid>"}'
Revert Slide
Request body:
RevertSlideRequest. Response: AcceptImageEditResponse.
Reverts the slide to a previous version using
history_entry_id from slide history.
curl -X POST "$LAYERPROOF_BASE_URL/api/v2/projects/<project_id>/slides/<slide_id>/revert" \ -H "Content-Type: application/json" \ -H "X-API-KEY: $LAYERPROOF_API_KEY" \ -d '{"history_entry_id":"<history_entry_uuid>"}'
Remove Objects (async)
Request body:
ObjectRemovalRequest. Response: TriggerWorkflowResponse.
Triggers AI-powered object removal. Optional
mask_path for mask-based removal. Poll jobs; when DONE, call accept-image-edit with live_object_id.
curl -X POST "$LAYERPROOF_BASE_URL/api/v2/projects/<project_id>/slides/<slide_id>/object-removal" \ -H "Content-Type: application/json" \ -H "X-API-KEY: $LAYERPROOF_API_KEY" \ -d '{"input_image_path":"/slides/slide-1.png"}'
With mask:
curl -X POST "$LAYERPROOF_BASE_URL/api/v2/projects/<project_id>/slides/<slide_id>/object-removal" \ -H "Content-Type: application/json" \ -H "X-API-KEY: $LAYERPROOF_API_KEY" \ -d '{"input_image_path":"/slides/slide-1.png","mask_path":"/masks/mask.png"}'
Extract Text (async)
Request body:
ExtractTextRequest (optional). Response: TriggerWorkflowResponse.
Performs OCR, removes text from image via inpainting, creates editable Konva text nodes. Poll
GET /api/v2/jobs/{activityId} for status.
curl -X POST "$LAYERPROOF_BASE_URL/api/v2/projects/<project_id>/slides/<slide_id>/extract-text" \ -H "Content-Type: application/json" \ -H "X-API-KEY: $LAYERPROOF_API_KEY" \ -d '{}'
With optional node:
curl -X POST "$LAYERPROOF_BASE_URL/api/v2/projects/<project_id>/slides/<slide_id>/extract-text" \ -H "Content-Type: application/json" \ -H "X-API-KEY: $LAYERPROOF_API_KEY" \ -d '{"node_id":"node-1","node_image_path":"/nodes/node1.png"}'
Save Konva Nodes
Request body:
SaveKonvaNodesRequest. Response: 200, no body.
Persists Konva canvas nodes and order (positions, layer order, flattened image path).
curl -X PUT "$LAYERPROOF_BASE_URL/api/v2/projects/<project_id>/slides/<slide_id>/konva-nodes" \ -H "Content-Type: application/json" \ -H "X-API-KEY: $LAYERPROOF_API_KEY" \ -d '{"konva_nodes":{},"konva_order":[]}'
Agent behavior
When the user asks to edit slides (image edit, accept edit, revert, remove objects, extract text, save canvas), do the following.
1. Choose the right endpoint
| User intent | Endpoint | Method |
|---|---|---|
| Edit slide image with AI instruction | | POST |
| Accept edited image after workflow completes | | POST |
| Revert slide to previous version | | POST |
| Remove objects from slide image (AI) | | POST |
| Extract text from slide (OCR + inpainting) | | POST |
| Save Konva canvas nodes/order | | PUT |
All paths require
projectId and slideId (replace placeholders with actual UUIDs).
2. Build and run the request
Step 1 — Check environment variables first. Before running any curl command, verify both
LAYERPROOF_BASE_URL and LAYERPROOF_API_KEY are set on the user's machine:
if [[ -z "${LAYERPROOF_BASE_URL}" ]]; then echo "ERROR: LAYERPROOF_BASE_URL is not set." return 1 fi if [[ -z "${LAYERPROOF_API_KEY}" ]]; then echo "ERROR: LAYERPROOF_API_KEY is not set." return 1 fi
If running from a project directory with a
.env.local file, load it first:
if [[ -f .env.local ]]; then set -a source .env.local set +a fi
Step 2 — Auth: Every request must include
X-API-KEY: $LAYERPROOF_API_KEY. Read LAYERPROOF_BASE_URL and LAYERPROOF_API_KEY from the environment; if missing, tell the user to set them.
Step 3 — Path: Resolve project_id and slide_id from context (e.g. from project/slide-deck list or user input). If missing, ask the user.
Step 4 — POST/PUT: Build JSON body from the types above. Use -X POST or -X PUT, -H "Content-Type: application/json", and -d '...'. Run the curl and show the result.
3. After async endpoints (image-edit, object-removal, extract-text)
- Response includes
andactivity_id
. Tell the user the workflow was started.live_object_id - Suggest polling
untilGET $LAYERPROOF_BASE_URL/api/v2/jobs/<activity_id>
isstatus
orDONE
.CANCELED - For image-edit and object-removal: when DONE, tell the user to call accept-image-edit with
to apply the result.live_object_id
4. Response handling
- Always show the raw JSON response in a JSON code block; do not convert to a table.
- If the response contains a URL for an image (e.g.
), show the image and the JSON.image_path - On error (4xx/5xx), show the response body and status code; suggest fixing API key, projectId/slideId, or request body.
5. Example workflows
Workflow A — User: "Edit slide image in project X, slide Y: make the background darker."
- Choose
.POST /api/v2/projects/{projectId}/slides/{slideId}/image-edit - Resolve projectId and slideId (from user or ask).
- Build body:
(user may need to provide image path).{"instruction":"Make the background darker","input_image_path":"/path/to/slide/image"} - Run curl; show JSON. Mention polling jobs with
and calling accept-image-edit withactivity_id
when done.live_object_id
Workflow B — User: "Edit two slides: darker background on slide 1, remove the logo from slide 3; then revert slide 1 if I don’t like it."
- Resolve projectId; get slide ids from slide-deck GET deck (e.g.
,slides[0].id
).slides[2].id - For slide 1: POST
with.../slides/{slideId1}/image-edit
; capture{"instruction":"Make the background darker"}
andactivity_id_1
. For slide 3: POSTlive_object_id_1
with region/instruction; capture.../slides/{slideId3}/object-removal
andactivity_id_3
.live_object_id_3 - Poll
andGET /api/v2/jobs/{activity_id_1}
until both DONE. If either fails, report which slide and reason..../jobs/{activity_id_3} - POST
with.../slides/{slideId1}/accept-image-edit
; POST{"live_object_id":"<live_object_id_1>"}
with.../slides/{slideId3}/accept-image-edit
. Show updated slide images (GET deck or slide detail).{"live_object_id":"<live_object_id_3>"} - If user says "revert slide 1": GET slide history (if available) for slideId1 to get
; POSThistory_entry_id
with.../slides/{slideId1}/revert
. Confirm with GET deck.{"history_entry_id":"<id>"}
Workflow C — User: "Extract text from slide 2 and replace the old text (OCR + inpainting)."
- Resolve projectId and slideId for slide 2. POST
(body per API); capture.../slides/{slideId}/extract-text
.activity_id - Poll
until DONE. When DONE,GET /api/v2/jobs/{activity_id}
may contain extracted text or updated asset reference.output - If a follow-up accept or apply step is required (e.g. accept-image-edit), use the returned
; otherwise show the result (e.g. updated slide or transcript) from GET deck.live_object_id
Response format (required)
- (if response contains url to show image) please show image and show json response instead of table
- Always show the raw JSON response (verbatim) in a JSON code block.
- If the response contains a URL for an image, render/show the image and also show the JSON response (do not convert to a table).