{"owner":"zhongerxin","repo":"Cowart","hasSkills":true,"totalSkillsCount":10,"totalTokensCount":6121,"categories":["plugin-manifest","mcp-config","marketplace","anthropic-skill"],"hasMcp":true,"mcpConfig":{"$schema":"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json","mcpServers":{"cowart_mcp":{"type":"stdio","command":"node","args":["./scripts/start-mcp.mjs"],"cwd":"./"}}},"found":["plugin.json","mcp.json",".codex-plugin/plugin.json",".agents/plugins/marketplace.json","skills/cowart-open-canvas/agents/openai.yaml","skills/cowart-image-gen/agents/openai.yaml","skills/cowart-image-edit/agents/openai.yaml","skills/cowart-image-gen/SKILL.md","skills/cowart-image-edit/SKILL.md","skills/cowart-open-canvas/SKILL.md"],"skills":{"plugin.json":"{\n  \"$schema\": \"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json\",\n  \"name\": \"cowart\",\n  \"version\": \"0.1.38\",\n  \"description\": \"A native fullscreen tldraw canvas for images, HTML, Slides and AI motion films. Open the canvas with Cowart MCP and reuse it for generation and playback.\",\n  \"author\": {\n    \"name\": \"ZHONG XIN\",\n    \"email\": \"zhongxin123456@gmail.com\",\n    \"url\": \"https://www.jiqiren.ai\"\n  },\n  \"homepage\": \"https://www.jiqiren.ai\",\n  \"repository\": \"https://github.com/zhongerxin/Cowart\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"canvas\",\n    \"tldraw\",\n    \"whiteboard\",\n    \"image-generation\",\n    \"visual-collaboration\"\n  ],\n  \"extensions\": {\n    \"com.openai\": {\n      \"interface\": {\n        \"displayName\": \"Cowart\",\n        \"shortDescription\": \"Your fullscreen project canvas\",\n        \"longDescription\": \"Cowart brings a native tldraw canvas into Codex for visual planning and creative iteration. Open Cowart from global navigation and pin it with the host pin control. The sidebar opens a single canvas in the system Documents/Cowart folder, creating the first page when needed. Project conversations with projectDir keep their own project canvas. Image, HTML, Slides, AI film and annotation workflows reuse the open canvas.\",\n        \"developerName\": \"ZHONG XIN\",\n        \"category\": \"Productivity\",\n        \"websiteURL\": \"https://www.jiqiren.ai\",\n        \"brandColor\": \"#25BFEF\",\n        \"logo\": \"./assets/app-icon.png\",\n        \"composerIcon\": \"./assets/app-icon.png\",\n        \"capabilities\": [\n          \"Fullscreen canvas\",\n          \"Sidebar entrypoint\",\n          \"AI image generation\",\n          \"Annotation-driven editing\",\n          \"Project-local persistence\",\n          \"AI motion films with playback\"\n        ],\n        \"defaultPrompt\": [\n          \"Open the Cowart canvas for this project.\",\n          \"Use my Cowart annotation screenshot to generate a clean revised image beside the original.\",\n          \"Generate a new image into the selected Cowart AI image holder.\",\n          \"Generate an AI motion film into the selected Cowart film holder using cowart-film-gen.\"\n        ]\n      }\n    }\n  }\n}\n","mcp.json":"{\n  \"$schema\": \"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json\",\n  \"mcpServers\": {\n    \"cowart_mcp\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\n        \"./scripts/start-mcp.mjs\"\n      ],\n      \"cwd\": \"./\"\n    }\n  }\n}\n",".codex-plugin/plugin.json":"{\n  \"name\": \"cowart\",\n  \"version\": \"0.1.38\",\n  \"description\": \"A native fullscreen tldraw canvas for images, HTML, Slides and AI motion films. Open the canvas with Cowart MCP and reuse it for generation and playback.\",\n  \"author\": {\n    \"name\": \"ZHONG XIN\",\n    \"email\": \"zhongxin123456@gmail.com\",\n    \"url\": \"https://www.jiqiren.ai\"\n  },\n  \"homepage\": \"https://www.jiqiren.ai\",\n  \"repository\": \"https://github.com/zhongerxin/Cowart\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"canvas\",\n    \"tldraw\",\n    \"whiteboard\",\n    \"image-generation\",\n    \"visual-collaboration\"\n  ],\n  \"skills\": \"./skills/\",\n  \"mcpServers\": \"./.mcp.json\",\n  \"interface\": {\n    \"displayName\": \"Cowart\",\n    \"shortDescription\": \"Your fullscreen project canvas\",\n    \"longDescription\": \"Cowart brings a native tldraw canvas into Codex for visual planning and creative iteration. Open Cowart from global navigation and pin it with the host pin control. The sidebar opens a single canvas in the system Documents/Cowart folder, creating the first page when needed. Project conversations with projectDir keep their own project canvas. Image, HTML, Slides, AI film and annotation workflows reuse the open canvas.\",\n    \"developerName\": \"ZHONG XIN\",\n    \"category\": \"Productivity\",\n    \"websiteURL\": \"https://www.jiqiren.ai\",\n    \"brandColor\": \"#25BFEF\",\n    \"logo\": \"./assets/app-icon.png\",\n    \"composerIcon\": \"./assets/app-icon.png\",\n    \"capabilities\": [\n      \"Fullscreen canvas\",\n      \"Sidebar entrypoint\",\n      \"AI image generation\",\n      \"Annotation-driven editing\",\n      \"Project-local persistence\",\n      \"AI motion films with playback\"\n    ],\n    \"defaultPrompt\": [\n      \"Open the Cowart canvas for this project.\",\n      \"Use my Cowart annotation screenshot to generate a clean revised image beside the original.\",\n      \"Generate a new image into the selected Cowart AI image holder.\",\n      \"Generate an AI motion film into the selected Cowart film holder using cowart-film-gen.\"\n    ]\n  }\n}\n",".agents/plugins/marketplace.json":"{\n  \"name\": \"cowart-github\",\n  \"interface\": {\n    \"displayName\": \"Cowart GitHub\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"cowart\",\n      \"source\": {\n        \"source\": \"local\",\n        \"path\": \".\"\n      },\n      \"policy\": {\n        \"installation\": \"AVAILABLE\",\n        \"authentication\": \"ON_INSTALL\"\n      },\n      \"category\": \"Productivity\"\n    }\n  ]\n}\n","skills/cowart-open-canvas/agents/openai.yaml":"interface:\n  display_name: \"Cowart Open Canvas\"\n  short_description: \"Open the Cowart infinite-canvas widget\"\n  default_prompt: \"Use $cowart:cowart-open-canvas to open the Cowart infinite-canvas widget.\"\n","skills/cowart-image-gen/agents/openai.yaml":"interface:\n  display_name: \"Cowart Image Gen\"\n  short_description: \"Replace a selected Cowart AI holder with a generated image\"\n  default_prompt: \"Use $cowart:cowart-image-gen to replace the selected Cowart AI image holder with a generated image.\"\n\npolicy:\n  allow_implicit_invocation: true\n","skills/cowart-image-edit/agents/openai.yaml":"interface:\n  display_name: \"Cowart Image Edit\"\n  short_description: \"Generate revised images from annotated screenshots\"\n  default_prompt: \"Use $cowart:cowart-image-edit to generate revised AI images from the Cowart 批注 screenshots I provide and place each result beside its original.\"\n","skills/cowart-image-gen/SKILL.md":"---\nname: cowart-image-gen\ndescription: Generate and place a final AI bitmap on the Cowart canvas, replacing a selected AI 图片 holder or inserting the image into the current page.\n---\n\n# Cowart Image Gen\n\nUse this skill when the user wants an AI-generated image placed onto the Cowart canvas. A selected `AI 图片` holder gives a precise size and placement target, but it is not required. By default, a selected holder is a temporary target and should be replaced by the generated image.\n\n## Preconditions\n\nEnsure the `cowart_mcp` tools required by this workflow are available. Do not call `render_cowart_canvas_widget` as a routine prerequisite: requests sent from the Cowart widget already have an open canvas, and the existing widget synchronizes inserted images from MCP-backed storage. If the user separately asks to open, reopen, or explicitly refresh the canvas, handle that request once with the canvas-opening workflow.\n\nCowart state is read and written through Cowart MCP tools, not through a localhost browser service.\n\nNew holders are tldraw `frame` shapes with:\n\n```json\n{\n  \"type\": \"frame\",\n  \"meta\": {\n    \"cowartAiImageHolder\": true\n  }\n}\n```\n\nOlder canvases may still contain legacy `geo` rectangle holders with the same\nmeta flag. Support both shapes.\n\n## Workflow\n\nFor a follow-up from Cowart's sidebar canvas, use the exact `projectDir` and `canvasDir` in the Cowart context/message for all Cowart tools. These paths can differ from the conversation working directory. In ordinary project conversations, keep using the active user project as before.\n\n1. Read the selected shape from Cowart with the MCP `get_cowart_selection` tool. Pass the active user project directory as `projectDir`.\n\n2. Check whether exactly one selected shape is an AI image holder. A holder is any selected shape with either:\n\n   ```text\n   isAiImageHolder: true\n   ```\n\n   or:\n\n   ```text\n   meta.cowartAiImageHolder: true\n   ```\n\n   If yes, use the holder replacement workflow below. If not, do not ask the user to select a holder; use the standalone workflow below and insert the generated image into the current Cowart page.\n\n3. Choose the placement workflow.\n\n   Holder replacement workflow: use the selected holder's `props.w` and `props.h` as the size contract for both generation and placement. Before generating, derive and keep these values:\n\n   - `targetWidth`: selected holder `props.w`\n   - `targetHeight`: selected holder `props.h`\n   - `targetAspectRatio`: the reduced `targetWidth:targetHeight` ratio when it maps cleanly, plus the decimal `targetWidth / targetHeight`\n\n   If the selected holder matches a Cowart ratio preset such as `1:1`, `3:2`, `2:3`, `4:3`, `3:4`, `16:9`, or `9:16`, use that preset label as the human-readable aspect ratio. The generated image should be composed for this target size and aspect ratio, and should not rely on later stretching or cropping to fit the holder.\n\n   The generated image should replace the selected holder as a normal tldraw image shape:\n\n   - `parentId`: same parent as the holder\n   - `x`, `y`, `rotation`: same as the holder\n   - `props.w`, `props.h`: same as the holder\n\n   This leaves the final canvas with an image shape at the holder's position, not an AI holder that contains an image. Only preserve the holder when the user explicitly asks to keep the reusable slot.\n\n   Standalone workflow: when no AI holder is selected, generate the image anyway and insert it as a normal image shape on the current page. Prefer the current page from Cowart view state; if there is a selected non-holder shape and it is useful as context, place the image beside it, otherwise place it in a clear page area. If the user requested a size or aspect ratio, pass that size and ratio into generation and use it for display. Otherwise, use the generated bitmap's natural aspect ratio and a practical display width such as 512 canvas units.\n\n4. Generate the bitmap with the built-in `imagegen` skill unless the user explicitly requests another image path. If the requested asset needs visible copy, labels, poster text, ad text, UI text, or typography, include that text directly in the image generation prompt and let the image model produce the final bitmap. Do not default to generating a text-free background and then adding text locally unless the user explicitly asks for local typography, deterministic text overlay, SVG/vector output, or another non-imagegen layout step.\n\n   For the holder workflow, the image generation request must explicitly include the selected holder's target size and aspect ratio. Add this information to the model prompt, for example:\n\n   ```text\n   Target canvas slot: 512 x 683 canvas units.\n   Target aspect ratio: 3:4 (0.75 width/height).\n   Compose the final bitmap for this portrait ratio so it fits the slot without cropping or stretching.\n   ```\n\n   If the image generation tool or model accepts size or aspect-ratio parameters, pass the closest supported option in addition to the prompt text. If only prompt text is available, the prompt text must still include `targetWidth`, `targetHeight`, and `targetAspectRatio`.\n\n   Resolve the actual local output image carefully before inserting it into Cowart. Do not assume the built-in image generation flow always writes a fresh file under `$CODEX_HOME/generated_images`.\n\n   Preferred resolution order:\n\n   - Use the exact local image path returned by the current image generation tool call when one is available.\n   - If no new file path is returned, inspect the current Codex session JSONL for the current request and extract the PNG/base64 payload from the latest `image_generation_call.result`, then write it to a timestamped output filename.\n   - Use `$CODEX_HOME/generated_images` only when you can prove the file was created by the current request, for example by matching its timestamp after this generation step. Never pick an older image merely because it is the newest file in a stale generated_images directory.\n\n   Before inserting the resolved file into Cowart, visually inspect the local bitmap and confirm it is the newly generated image for this request, not a stale generated asset.\n\n   For project-bound output, copy the resolved generated image into the selected page's asset folder:\n\n   ```text\n   canvas/pages/<page-id-without-page-prefix>/assets/\n   ```\n\n5. Insert the generated image as a new tldraw image shape.\n\n   For the holder replacement workflow, call `insert_cowart_image` with the holder id as `anchorShapeId` and leave `replaceAiImageHolder` unset or set it to `true`. The MCP tool will place the image exactly where the holder was and remove the holder shape:\n\n   - `type`: `image`\n   - `parentId`: same as holder parent\n   - `x`, `y`, `rotation`: same as holder\n   - `props.w`, `props.h`: same as holder\n   - `props.assetId`: the new image asset id\n   - `meta.cowartGeneratedForAiImageHolder`: holder shape id\n   - `meta.cowartReplacedAiImageHolder`: `true`\n\n   If the user explicitly asks to keep the AI holder reusable, call `insert_cowart_image` with `replaceAiImageHolder: false`; for frame holders that legacy mode inserts the generated image as a child of the frame.\n\n   For the standalone workflow, insert it into the current page as a normal image:\n\n   - `type`: `image`\n   - `parentId`: current page id, unless placing beside a selected non-holder shape requires the same parent\n   - `x`, `y`: a clear page area or beside the selected non-holder shape\n   - `rotation`: `0`\n   - `props.w`, `props.h`: display size matching the generated bitmap aspect ratio\n   - `props.assetId`: the new image asset id\n   - `meta.cowartGeneratedStandalone`: `true`\n\n6. Delete the selected holder by default as part of replacement. In the standalone workflow, do not create a holder first unless the user explicitly asks for one.\n\n7. Save through Cowart MCP. Prefer `insert_cowart_image` for inserting the generated bitmap, or use `save_cowart_canvas_state` only when you must update the whole tldraw snapshot.\n\n   Prefer page-local asset URLs in the image asset:\n\n   ```text\n   /page-assets/<page-id-without-page-prefix>/<filename>\n   ```\n\n8. Let the Cowart widget refresh from MCP-backed storage, then confirm the inserted shape id, final dimensions, target aspect ratio, saved asset path, and replaced holder id when the holder replacement workflow was used.\n\n## Notes\n\n- If the holder is a legacy rotated `geo` rectangle, preserve the same `rotation` on the replacement image.\n- If there is already a generated image inside the holder from an older Cowart version, replacing the holder should remove the holder and its child image shape, then create one normal image shape in the holder's former position.\n- Do not refuse generation solely because no `AI 图片` holder is selected. Generate the bitmap and insert it into the current Cowart page.\n- Never overwrite an existing asset file; use a timestamped filename.\n","skills/cowart-image-edit/SKILL.md":"---\nname: cowart-image-edit\ndescription: Generate revised AI images from user-supplied Cowart annotation screenshots and place each result beside its original without replacing, moving, hiding, or deleting existing images or annotations.\n---\n\n# Cowart Image Edit\n\nUse this skill to turn user-provided Cowart 批注 screenshots into revised AI-generated bitmaps placed next to the corresponding original images.\n\n## Preconditions\n\nEnsure the `cowart_mcp` tools required by this workflow are available. Do not call `render_cowart_canvas_widget` as a routine prerequisite: annotation requests sent from the Cowart widget already have an open canvas, and the existing widget synchronizes inserted results from MCP-backed storage. If the user separately asks to open, reopen, or explicitly refresh the canvas, handle that request once with the canvas-opening workflow.\n\nCowart state is read and written through Cowart MCP tools, not through a localhost browser service.\n\nThe user is responsible for providing the relevant screenshot(s). Do not auto-capture the current canvas and do not scan the whole canvas to infer edit requests; a canvas may contain many images with different annotations.\n\n## Workflow\n\nFor a follow-up from Cowart's sidebar canvas, use the exact `projectDir` and `canvasDir` in the Cowart context/message for all Cowart tools. These paths can differ from the conversation working directory. In ordinary project conversations, keep using the active user project as before.\n\n1. Read the user-provided screenshot(s).\n\n   Treat each screenshot as the authoritative edit brief for one output image unless the user says multiple screenshots belong to the same image.\n\n   If the user provides multiple screenshots, process them independently and keep their generated outputs separate. Do not merge annotations across screenshots unless explicitly requested.\n\n2. Extract the edit requirements from each screenshot.\n\n   Read visible 批注 labels, arrows, and nearby edit notes from the screenshot itself. Use the arrow tip or marked region to understand where each note applies.\n\n   Ignore editor chrome such as toolbars, blue selection outlines, resize handles, cursor icons, and unrelated neighboring images.\n\n3. Choose the source image for generation.\n\n   Use the clean underlying image content visible in the provided screenshot as the visual base whenever possible.\n\n   If the screenshot is too cropped, obstructed, or low-resolution to serve as a good image base, ask the user for the original image export or a cleaner screenshot of that specific image.\n\n   Do not read the current Cowart canvas to discover edit intent. Use the screenshot for the requested changes. Cowart state may be read later only to place the generated result without covering existing content.\n\n4. Prepare image-generation input.\n\n   Use the provided screenshot, plus a cleaner source image if the user supplied one.\n\n   The generation prompt should:\n\n   - apply the 批注 text as edit instructions\n   - preserve the original image's subject, composition, aspect ratio, and style unless an annotation asks otherwise\n   - remove all annotation artifacts from the output, including red arrows, labels, blue selection outlines, handles, and tool UI\n   - output only the revised clean image\n\n5. Generate a new bitmap.\n\n   Use the built-in image generation flow available in the current environment. Do not overwrite the source image file. Save the new bitmap with a timestamped filename, for example:\n\n   ```text\n   annotation-edit-20260620-153012.png\n   ```\n\n   Resolve the actual local output image carefully before inserting it into Cowart. Do not assume the built-in image generation flow always writes a fresh file under `$CODEX_HOME/generated_images`.\n\n   Preferred resolution order:\n\n   - Use the exact local image path returned by the current image generation tool call when one is available.\n   - If no new file path is returned, inspect the current Codex session JSONL for the current request and extract the PNG/base64 payload from the latest `image_generation_call.result`, then write it to the timestamped output filename.\n   - Use `$CODEX_HOME/generated_images` only when you can prove the file was created by the current request, for example by matching its timestamp after this generation step. Never pick an older image merely because it is the newest file in a stale generated_images directory.\n\n   Before inserting the resolved file into Cowart, visually inspect the local bitmap and confirm it is the newly generated revised image for this screenshot, not a stale generated asset.\n\n6. Insert the revised image beside the original with Cowart MCP.\n\n   Prefer the Cowart MCP `insert_cowart_image` tool. Do not hand-write\n   tldraw `asset` / `shape` records or fractional `index` keys unless the MCP\n   tool is unavailable. The tool copies the bitmap into the page-local assets\n   folder, creates the tldraw image asset and image shape, generates a valid\n   tldraw fractional index, places the image beside the anchor while avoiding\n   overlaps, and saves through the project-backed Cowart canvas files.\n\n   Add a new tldraw image asset and a new image shape. Do not update, remove, hide, reparent, or reorder the original image, the original `AI 图片` frame, or any annotation shapes.\n\n   Prefer a clear placement anchor when one is already available:\n\n   - If the user has selected the original image, use that image as the anchor.\n   - If the user has selected the original `AI 图片` frame, use that frame as the anchor.\n   - If the screenshot clearly shows the original image and there is a unique matching generated/original image or `AI 图片` frame on the current Cowart page, use that as the anchor without asking the user to select it.\n   - If there are multiple screenshots/outputs and the matching anchors are not uniquely identifiable, ask the user to select each corresponding anchor or provide an explicit placement order.\n   - If no anchor is clear and the user has not required a specific side-by-side comparison, place the result in a nearby clear area on the current page where it does not cover, move, hide, or delete the original image or annotations.\n\n   Placement rules:\n\n   - If the source image is inside an `AI 图片` frame, use the frame's page-level bounds as the anchor and place the new image as a sibling of that frame.\n   - Otherwise use the source image's own bounds and parent.\n   - When the annotated source appears to have earlier revision images nearby, prefer placing the new revised image to the right of the currently annotated/source image, because older annotation outputs may already live on the left.\n   - Place the new image to the right of the anchor with a margin of about `40` canvas units.\n   - Match the displayed width and height of the anchor unless the user asks for a different size.\n   - If that position would overlap existing content, keep moving right by `anchor width + 40` until the new image is clear.\n   - If using a clear-area fallback with no anchor, keep the generated image near the annotated source page, match the likely source image size when known, and choose a position that does not overlap existing shapes.\n\n   Recommended shape metadata:\n\n   ```json\n   {\n     \"cowartGeneratedFromAnnotationEdit\": true,\n     \"cowartAnnotationSourceShapeId\": \"<selected source image or frame id>\",\n     \"cowartAnnotationScreenshot\": \"<source screenshot file name when available>\"\n   }\n   ```\n\n7. Save through Cowart.\n\n   Only do Cowart state access after the bitmap is generated. Use this access only to insert the new image beside the anchor or in a nearby clear area, not to discover edit intent.\n\n   Preferred MCP call shape:\n\n   ```json\n   {\n     \"imagePath\": \"/absolute/path/to/annotation-edit-20260620-153012.png\",\n     \"projectDir\": \"/absolute/path/to/user/codex-project\",\n     \"anchorShapeId\": \"<selected source image or frame id>\",\n     \"placement\": \"right\",\n     \"margin\": 40,\n     \"matchAnchor\": true,\n     \"fileName\": \"annotation-edit-20260620-153012.png\",\n     \"annotationScreenshot\": \"<source screenshot file name when available>\",\n     \"shapeMeta\": {\n       \"cowartGeneratedFromAnnotationEdit\": true\n     },\n     \"altText\": \"Revised image generated from Cowart annotation screenshot\"\n   }\n   ```\n\n   The MCP tool must return the new `assetId`, `shapeId`, saved asset path,\n   page id, bounds, and generated `index`. Confirm that the returned `index` is\n   a valid tldraw fractional index and not a custom descriptive string.\n\n   Fallback only when `insert_cowart_image` is unavailable: update the required store snapshot and save it with `save_cowart_canvas_state`.\n\n   In fallback mode, use page-local image asset URLs:\n\n   ```text\n   /page-assets/<page-dir>/<filename>\n   ```\n\n   Cowart's MCP storage layer will preserve per-page snapshots under:\n\n   ```text\n   canvas/pages/<page-id-without-page-prefix>/cowart-canvas.json\n   ```\n\n8. Verify visually.\n\n   Let the Cowart widget refresh from MCP-backed storage, then confirm:\n\n   - the original image is still in the same place\n   - the original 批注 arrows and labels are still visible\n   - the new revised image appears beside the original\n   - the new image does not include annotation arrows, labels, selections, or UI chrome\n\n## Guardrails\n\n- Never replace the original image unless the user explicitly asks for replacement.\n- Never delete or move annotation shapes; they are the visible edit brief.\n- Never put the revised image inside the original `AI 图片` frame, because that can cover the old image and make the before/after comparison harder.\n- Never auto-capture or scan the current canvas for edit intent; use the screenshot(s) supplied by the user.\n- If the annotations contradict each other, generate the most literal combined interpretation and mention the ambiguity.\n- If a supplied screenshot shows selected-state outlines or toolbar UI, treat them as context only, not as content to generate.\n","skills/cowart-open-canvas/SKILL.md":"---\nname: cowart-open-canvas\ndescription: Open, reopen, or explicitly refresh the native Cowart canvas when the user asks to see it, or when a bare @Cowart invocation has no other requested workflow.\n---\n\n# Cowart Open Canvas\n\nThe actual canvas-opening capability is the `cowart_mcp` MCP server and its `render_cowart_canvas_widget` tool. Use this skill when the user asks to open, reopen, or explicitly refresh the canvas. A bare `@Cowart` invocation with no other actionable request may also open the canvas. Do not use this skill as a prerequisite for image generation, annotation editing, HTML, Slides, or follow-up requests sent from an already-open Cowart widget.\n\n## Workflow\n\n1. Ensure the `cowart_mcp` MCP server is loaded or discoverable and that its `render_cowart_canvas_widget` tool is available. The host may expose the complete tool name as `mcp__cowart_mcp__render_cowart_canvas_widget`. Call the tool once for the user's open, reopen, or explicit refresh request. Pass the user's active Codex workspace as `projectDir`; do not pass the Cowart plugin repository directory.\n\n```json\n{\n  \"projectDir\": \"/absolute/path/to/user/codex-project\"\n}\n```\n\nThe tool returns `openai/outputTemplate: ui://widget/cowart/canvas.html`, which tells Codex to render the widget directly. Do not start `scripts/start-canvas.sh` or open a localhost URL for normal use.\n\nCowart also declares an OpenAI MCP Extensions `global` entrypoint, so supported hosts can show it in navigation and let the user pin it. Clicking that entrypoint sends `{}` and opens the canvas directly at `<system Documents>/Cowart/canvas/`. This is one shared local canvas with multiple pages; the first page is created only when none exists. There is no project picker. Empty arguments never infer a workspace from the MCP process directory. When a workspace is known in chat, keep passing `projectDir` to open its canvas directly. Cowart declares only the `fullscreen` display mode; in a conversation, the host may place fullscreen apps in the content side panel.\n\nFor follow-ups from the global app, use the `projectDir` and `canvasDir` supplied in Cowart's model context or follow-up message. Do not substitute the global app thread's own working directory for the open canvas.\n\n2. Confirm the widget opens for the user. The canvas data is stored in the active project:\n\n```text\ncanvas/pages/<page-id>/cowart-canvas.json\ncanvas/pages/<page-id>/assets/\n```\n\n3. If the MCP tool is not visible in the current turn, use tool discovery for Cowart widget/render capabilities and retry within the same task after an explicit Cowart canvas invocation. Do not claim that a new task is required merely because one turn did not expose the tool. Only suggest a new Codex task when the plugin was just installed or upgraded and the MCP schema is still unavailable after discovery and an explicit retry.\n\n## Constraints\n\nDo not call `render_cowart_canvas_widget` again merely because another Cowart skill applies or an existing widget sends a follow-up request. The existing widget synchronizes MCP-backed canvas changes itself. Do not launch the old local web service, inspect canvas files, run builds, check storage layout, take screenshots, or perform other validation steps unless opening the widget fails or the user explicitly asks for those checks. The `scripts/start-canvas.sh` path is now only a local-development fallback.\n"},"files":{"plugin.json":"{\n  \"$schema\": \"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json\",\n  \"name\": \"cowart\",\n  \"version\": \"0.1.38\",\n  \"description\": \"A native fullscreen tldraw canvas for images, HTML, Slides and AI motion films. Open the canvas with Cowart MCP and reuse it for generation and playback.\",\n  \"author\": {\n    \"name\": \"ZHONG XIN\",\n    \"email\": \"zhongxin123456@gmail.com\",\n    \"url\": \"https://www.jiqiren.ai\"\n  },\n  \"homepage\": \"https://www.jiqiren.ai\",\n  \"repository\": \"https://github.com/zhongerxin/Cowart\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"canvas\",\n    \"tldraw\",\n    \"whiteboard\",\n    \"image-generation\",\n    \"visual-collaboration\"\n  ],\n  \"extensions\": {\n    \"com.openai\": {\n      \"interface\": {\n        \"displayName\": \"Cowart\",\n        \"shortDescription\": \"Your fullscreen project canvas\",\n        \"longDescription\": \"Cowart brings a native tldraw canvas into Codex for visual planning and creative iteration. Open Cowart from global navigation and pin it with the host pin control. The sidebar opens a single canvas in the system Documents/Cowart folder, creating the first page when needed. Project conversations with projectDir keep their own project canvas. Image, HTML, Slides, AI film and annotation workflows reuse the open canvas.\",\n        \"developerName\": \"ZHONG XIN\",\n        \"category\": \"Productivity\",\n        \"websiteURL\": \"https://www.jiqiren.ai\",\n        \"brandColor\": \"#25BFEF\",\n        \"logo\": \"./assets/app-icon.png\",\n        \"composerIcon\": \"./assets/app-icon.png\",\n        \"capabilities\": [\n          \"Fullscreen canvas\",\n          \"Sidebar entrypoint\",\n          \"AI image generation\",\n          \"Annotation-driven editing\",\n          \"Project-local persistence\",\n          \"AI motion films with playback\"\n        ],\n        \"defaultPrompt\": [\n          \"Open the Cowart canvas for this project.\",\n          \"Use my Cowart annotation screenshot to generate a clean revised image beside the original.\",\n          \"Generate a new image into the selected Cowart AI image holder.\",\n          \"Generate an AI motion film into the selected Cowart film holder using cowart-film-gen.\"\n        ]\n      }\n    }\n  }\n}\n","mcp.json":"{\n  \"$schema\": \"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json\",\n  \"mcpServers\": {\n    \"cowart_mcp\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\n        \"./scripts/start-mcp.mjs\"\n      ],\n      \"cwd\": \"./\"\n    }\n  }\n}\n",".codex-plugin/plugin.json":"{\n  \"name\": \"cowart\",\n  \"version\": \"0.1.38\",\n  \"description\": \"A native fullscreen tldraw canvas for images, HTML, Slides and AI motion films. Open the canvas with Cowart MCP and reuse it for generation and playback.\",\n  \"author\": {\n    \"name\": \"ZHONG XIN\",\n    \"email\": \"zhongxin123456@gmail.com\",\n    \"url\": \"https://www.jiqiren.ai\"\n  },\n  \"homepage\": \"https://www.jiqiren.ai\",\n  \"repository\": \"https://github.com/zhongerxin/Cowart\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"canvas\",\n    \"tldraw\",\n    \"whiteboard\",\n    \"image-generation\",\n    \"visual-collaboration\"\n  ],\n  \"skills\": \"./skills/\",\n  \"mcpServers\": \"./.mcp.json\",\n  \"interface\": {\n    \"displayName\": \"Cowart\",\n    \"shortDescription\": \"Your fullscreen project canvas\",\n    \"longDescription\": \"Cowart brings a native tldraw canvas into Codex for visual planning and creative iteration. Open Cowart from global navigation and pin it with the host pin control. The sidebar opens a single canvas in the system Documents/Cowart folder, creating the first page when needed. Project conversations with projectDir keep their own project canvas. Image, HTML, Slides, AI film and annotation workflows reuse the open canvas.\",\n    \"developerName\": \"ZHONG XIN\",\n    \"category\": \"Productivity\",\n    \"websiteURL\": \"https://www.jiqiren.ai\",\n    \"brandColor\": \"#25BFEF\",\n    \"logo\": \"./assets/app-icon.png\",\n    \"composerIcon\": \"./assets/app-icon.png\",\n    \"capabilities\": [\n      \"Fullscreen canvas\",\n      \"Sidebar entrypoint\",\n      \"AI image generation\",\n      \"Annotation-driven editing\",\n      \"Project-local persistence\",\n      \"AI motion films with playback\"\n    ],\n    \"defaultPrompt\": [\n      \"Open the Cowart canvas for this project.\",\n      \"Use my Cowart annotation screenshot to generate a clean revised image beside the original.\",\n      \"Generate a new image into the selected Cowart AI image holder.\",\n      \"Generate an AI motion film into the selected Cowart film holder using cowart-film-gen.\"\n    ]\n  }\n}\n",".agents/plugins/marketplace.json":"{\n  \"name\": \"cowart-github\",\n  \"interface\": {\n    \"displayName\": \"Cowart GitHub\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"cowart\",\n      \"source\": {\n        \"source\": \"local\",\n        \"path\": \".\"\n      },\n      \"policy\": {\n        \"installation\": \"AVAILABLE\",\n        \"authentication\": \"ON_INSTALL\"\n      },\n      \"category\": \"Productivity\"\n    }\n  ]\n}\n","skills/cowart-open-canvas/agents/openai.yaml":"interface:\n  display_name: \"Cowart Open Canvas\"\n  short_description: \"Open the Cowart infinite-canvas widget\"\n  default_prompt: \"Use $cowart:cowart-open-canvas to open the Cowart infinite-canvas widget.\"\n","skills/cowart-image-gen/agents/openai.yaml":"interface:\n  display_name: \"Cowart Image Gen\"\n  short_description: \"Replace a selected Cowart AI holder with a generated image\"\n  default_prompt: \"Use $cowart:cowart-image-gen to replace the selected Cowart AI image holder with a generated image.\"\n\npolicy:\n  allow_implicit_invocation: true\n","skills/cowart-image-edit/agents/openai.yaml":"interface:\n  display_name: \"Cowart Image Edit\"\n  short_description: \"Generate revised images from annotated screenshots\"\n  default_prompt: \"Use $cowart:cowart-image-edit to generate revised AI images from the Cowart 批注 screenshots I provide and place each result beside its original.\"\n","skills/cowart-image-gen/SKILL.md":"---\nname: cowart-image-gen\ndescription: Generate and place a final AI bitmap on the Cowart canvas, replacing a selected AI 图片 holder or inserting the image into the current page.\n---\n\n# Cowart Image Gen\n\nUse this skill when the user wants an AI-generated image placed onto the Cowart canvas. A selected `AI 图片` holder gives a precise size and placement target, but it is not required. By default, a selected holder is a temporary target and should be replaced by the generated image.\n\n## Preconditions\n\nEnsure the `cowart_mcp` tools required by this workflow are available. Do not call `render_cowart_canvas_widget` as a routine prerequisite: requests sent from the Cowart widget already have an open canvas, and the existing widget synchronizes inserted images from MCP-backed storage. If the user separately asks to open, reopen, or explicitly refresh the canvas, handle that request once with the canvas-opening workflow.\n\nCowart state is read and written through Cowart MCP tools, not through a localhost browser service.\n\nNew holders are tldraw `frame` shapes with:\n\n```json\n{\n  \"type\": \"frame\",\n  \"meta\": {\n    \"cowartAiImageHolder\": true\n  }\n}\n```\n\nOlder canvases may still contain legacy `geo` rectangle holders with the same\nmeta flag. Support both shapes.\n\n## Workflow\n\nFor a follow-up from Cowart's sidebar canvas, use the exact `projectDir` and `canvasDir` in the Cowart context/message for all Cowart tools. These paths can differ from the conversation working directory. In ordinary project conversations, keep using the active user project as before.\n\n1. Read the selected shape from Cowart with the MCP `get_cowart_selection` tool. Pass the active user project directory as `projectDir`.\n\n2. Check whether exactly one selected shape is an AI image holder. A holder is any selected shape with either:\n\n   ```text\n   isAiImageHolder: true\n   ```\n\n   or:\n\n   ```text\n   meta.cowartAiImageHolder: true\n   ```\n\n   If yes, use the holder replacement workflow below. If not, do not ask the user to select a holder; use the standalone workflow below and insert the generated image into the current Cowart page.\n\n3. Choose the placement workflow.\n\n   Holder replacement workflow: use the selected holder's `props.w` and `props.h` as the size contract for both generation and placement. Before generating, derive and keep these values:\n\n   - `targetWidth`: selected holder `props.w`\n   - `targetHeight`: selected holder `props.h`\n   - `targetAspectRatio`: the reduced `targetWidth:targetHeight` ratio when it maps cleanly, plus the decimal `targetWidth / targetHeight`\n\n   If the selected holder matches a Cowart ratio preset such as `1:1`, `3:2`, `2:3`, `4:3`, `3:4`, `16:9`, or `9:16`, use that preset label as the human-readable aspect ratio. The generated image should be composed for this target size and aspect ratio, and should not rely on later stretching or cropping to fit the holder.\n\n   The generated image should replace the selected holder as a normal tldraw image shape:\n\n   - `parentId`: same parent as the holder\n   - `x`, `y`, `rotation`: same as the holder\n   - `props.w`, `props.h`: same as the holder\n\n   This leaves the final canvas with an image shape at the holder's position, not an AI holder that contains an image. Only preserve the holder when the user explicitly asks to keep the reusable slot.\n\n   Standalone workflow: when no AI holder is selected, generate the image anyway and insert it as a normal image shape on the current page. Prefer the current page from Cowart view state; if there is a selected non-holder shape and it is useful as context, place the image beside it, otherwise place it in a clear page area. If the user requested a size or aspect ratio, pass that size and ratio into generation and use it for display. Otherwise, use the generated bitmap's natural aspect ratio and a practical display width such as 512 canvas units.\n\n4. Generate the bitmap with the built-in `imagegen` skill unless the user explicitly requests another image path. If the requested asset needs visible copy, labels, poster text, ad text, UI text, or typography, include that text directly in the image generation prompt and let the image model produce the final bitmap. Do not default to generating a text-free background and then adding text locally unless the user explicitly asks for local typography, deterministic text overlay, SVG/vector output, or another non-imagegen layout step.\n\n   For the holder workflow, the image generation request must explicitly include the selected holder's target size and aspect ratio. Add this information to the model prompt, for example:\n\n   ```text\n   Target canvas slot: 512 x 683 canvas units.\n   Target aspect ratio: 3:4 (0.75 width/height).\n   Compose the final bitmap for this portrait ratio so it fits the slot without cropping or stretching.\n   ```\n\n   If the image generation tool or model accepts size or aspect-ratio parameters, pass the closest supported option in addition to the prompt text. If only prompt text is available, the prompt text must still include `targetWidth`, `targetHeight`, and `targetAspectRatio`.\n\n   Resolve the actual local output image carefully before inserting it into Cowart. Do not assume the built-in image generation flow always writes a fresh file under `$CODEX_HOME/generated_images`.\n\n   Preferred resolution order:\n\n   - Use the exact local image path returned by the current image generation tool call when one is available.\n   - If no new file path is returned, inspect the current Codex session JSONL for the current request and extract the PNG/base64 payload from the latest `image_generation_call.result`, then write it to a timestamped output filename.\n   - Use `$CODEX_HOME/generated_images` only when you can prove the file was created by the current request, for example by matching its timestamp after this generation step. Never pick an older image merely because it is the newest file in a stale generated_images directory.\n\n   Before inserting the resolved file into Cowart, visually inspect the local bitmap and confirm it is the newly generated image for this request, not a stale generated asset.\n\n   For project-bound output, copy the resolved generated image into the selected page's asset folder:\n\n   ```text\n   canvas/pages/<page-id-without-page-prefix>/assets/\n   ```\n\n5. Insert the generated image as a new tldraw image shape.\n\n   For the holder replacement workflow, call `insert_cowart_image` with the holder id as `anchorShapeId` and leave `replaceAiImageHolder` unset or set it to `true`. The MCP tool will place the image exactly where the holder was and remove the holder shape:\n\n   - `type`: `image`\n   - `parentId`: same as holder parent\n   - `x`, `y`, `rotation`: same as holder\n   - `props.w`, `props.h`: same as holder\n   - `props.assetId`: the new image asset id\n   - `meta.cowartGeneratedForAiImageHolder`: holder shape id\n   - `meta.cowartReplacedAiImageHolder`: `true`\n\n   If the user explicitly asks to keep the AI holder reusable, call `insert_cowart_image` with `replaceAiImageHolder: false`; for frame holders that legacy mode inserts the generated image as a child of the frame.\n\n   For the standalone workflow, insert it into the current page as a normal image:\n\n   - `type`: `image`\n   - `parentId`: current page id, unless placing beside a selected non-holder shape requires the same parent\n   - `x`, `y`: a clear page area or beside the selected non-holder shape\n   - `rotation`: `0`\n   - `props.w`, `props.h`: display size matching the generated bitmap aspect ratio\n   - `props.assetId`: the new image asset id\n   - `meta.cowartGeneratedStandalone`: `true`\n\n6. Delete the selected holder by default as part of replacement. In the standalone workflow, do not create a holder first unless the user explicitly asks for one.\n\n7. Save through Cowart MCP. Prefer `insert_cowart_image` for inserting the generated bitmap, or use `save_cowart_canvas_state` only when you must update the whole tldraw snapshot.\n\n   Prefer page-local asset URLs in the image asset:\n\n   ```text\n   /page-assets/<page-id-without-page-prefix>/<filename>\n   ```\n\n8. Let the Cowart widget refresh from MCP-backed storage, then confirm the inserted shape id, final dimensions, target aspect ratio, saved asset path, and replaced holder id when the holder replacement workflow was used.\n\n## Notes\n\n- If the holder is a legacy rotated `geo` rectangle, preserve the same `rotation` on the replacement image.\n- If there is already a generated image inside the holder from an older Cowart version, replacing the holder should remove the holder and its child image shape, then create one normal image shape in the holder's former position.\n- Do not refuse generation solely because no `AI 图片` holder is selected. Generate the bitmap and insert it into the current Cowart page.\n- Never overwrite an existing asset file; use a timestamped filename.\n","skills/cowart-image-edit/SKILL.md":"---\nname: cowart-image-edit\ndescription: Generate revised AI images from user-supplied Cowart annotation screenshots and place each result beside its original without replacing, moving, hiding, or deleting existing images or annotations.\n---\n\n# Cowart Image Edit\n\nUse this skill to turn user-provided Cowart 批注 screenshots into revised AI-generated bitmaps placed next to the corresponding original images.\n\n## Preconditions\n\nEnsure the `cowart_mcp` tools required by this workflow are available. Do not call `render_cowart_canvas_widget` as a routine prerequisite: annotation requests sent from the Cowart widget already have an open canvas, and the existing widget synchronizes inserted results from MCP-backed storage. If the user separately asks to open, reopen, or explicitly refresh the canvas, handle that request once with the canvas-opening workflow.\n\nCowart state is read and written through Cowart MCP tools, not through a localhost browser service.\n\nThe user is responsible for providing the relevant screenshot(s). Do not auto-capture the current canvas and do not scan the whole canvas to infer edit requests; a canvas may contain many images with different annotations.\n\n## Workflow\n\nFor a follow-up from Cowart's sidebar canvas, use the exact `projectDir` and `canvasDir` in the Cowart context/message for all Cowart tools. These paths can differ from the conversation working directory. In ordinary project conversations, keep using the active user project as before.\n\n1. Read the user-provided screenshot(s).\n\n   Treat each screenshot as the authoritative edit brief for one output image unless the user says multiple screenshots belong to the same image.\n\n   If the user provides multiple screenshots, process them independently and keep their generated outputs separate. Do not merge annotations across screenshots unless explicitly requested.\n\n2. Extract the edit requirements from each screenshot.\n\n   Read visible 批注 labels, arrows, and nearby edit notes from the screenshot itself. Use the arrow tip or marked region to understand where each note applies.\n\n   Ignore editor chrome such as toolbars, blue selection outlines, resize handles, cursor icons, and unrelated neighboring images.\n\n3. Choose the source image for generation.\n\n   Use the clean underlying image content visible in the provided screenshot as the visual base whenever possible.\n\n   If the screenshot is too cropped, obstructed, or low-resolution to serve as a good image base, ask the user for the original image export or a cleaner screenshot of that specific image.\n\n   Do not read the current Cowart canvas to discover edit intent. Use the screenshot for the requested changes. Cowart state may be read later only to place the generated result without covering existing content.\n\n4. Prepare image-generation input.\n\n   Use the provided screenshot, plus a cleaner source image if the user supplied one.\n\n   The generation prompt should:\n\n   - apply the 批注 text as edit instructions\n   - preserve the original image's subject, composition, aspect ratio, and style unless an annotation asks otherwise\n   - remove all annotation artifacts from the output, including red arrows, labels, blue selection outlines, handles, and tool UI\n   - output only the revised clean image\n\n5. Generate a new bitmap.\n\n   Use the built-in image generation flow available in the current environment. Do not overwrite the source image file. Save the new bitmap with a timestamped filename, for example:\n\n   ```text\n   annotation-edit-20260620-153012.png\n   ```\n\n   Resolve the actual local output image carefully before inserting it into Cowart. Do not assume the built-in image generation flow always writes a fresh file under `$CODEX_HOME/generated_images`.\n\n   Preferred resolution order:\n\n   - Use the exact local image path returned by the current image generation tool call when one is available.\n   - If no new file path is returned, inspect the current Codex session JSONL for the current request and extract the PNG/base64 payload from the latest `image_generation_call.result`, then write it to the timestamped output filename.\n   - Use `$CODEX_HOME/generated_images` only when you can prove the file was created by the current request, for example by matching its timestamp after this generation step. Never pick an older image merely because it is the newest file in a stale generated_images directory.\n\n   Before inserting the resolved file into Cowart, visually inspect the local bitmap and confirm it is the newly generated revised image for this screenshot, not a stale generated asset.\n\n6. Insert the revised image beside the original with Cowart MCP.\n\n   Prefer the Cowart MCP `insert_cowart_image` tool. Do not hand-write\n   tldraw `asset` / `shape` records or fractional `index` keys unless the MCP\n   tool is unavailable. The tool copies the bitmap into the page-local assets\n   folder, creates the tldraw image asset and image shape, generates a valid\n   tldraw fractional index, places the image beside the anchor while avoiding\n   overlaps, and saves through the project-backed Cowart canvas files.\n\n   Add a new tldraw image asset and a new image shape. Do not update, remove, hide, reparent, or reorder the original image, the original `AI 图片` frame, or any annotation shapes.\n\n   Prefer a clear placement anchor when one is already available:\n\n   - If the user has selected the original image, use that image as the anchor.\n   - If the user has selected the original `AI 图片` frame, use that frame as the anchor.\n   - If the screenshot clearly shows the original image and there is a unique matching generated/original image or `AI 图片` frame on the current Cowart page, use that as the anchor without asking the user to select it.\n   - If there are multiple screenshots/outputs and the matching anchors are not uniquely identifiable, ask the user to select each corresponding anchor or provide an explicit placement order.\n   - If no anchor is clear and the user has not required a specific side-by-side comparison, place the result in a nearby clear area on the current page where it does not cover, move, hide, or delete the original image or annotations.\n\n   Placement rules:\n\n   - If the source image is inside an `AI 图片` frame, use the frame's page-level bounds as the anchor and place the new image as a sibling of that frame.\n   - Otherwise use the source image's own bounds and parent.\n   - When the annotated source appears to have earlier revision images nearby, prefer placing the new revised image to the right of the currently annotated/source image, because older annotation outputs may already live on the left.\n   - Place the new image to the right of the anchor with a margin of about `40` canvas units.\n   - Match the displayed width and height of the anchor unless the user asks for a different size.\n   - If that position would overlap existing content, keep moving right by `anchor width + 40` until the new image is clear.\n   - If using a clear-area fallback with no anchor, keep the generated image near the annotated source page, match the likely source image size when known, and choose a position that does not overlap existing shapes.\n\n   Recommended shape metadata:\n\n   ```json\n   {\n     \"cowartGeneratedFromAnnotationEdit\": true,\n     \"cowartAnnotationSourceShapeId\": \"<selected source image or frame id>\",\n     \"cowartAnnotationScreenshot\": \"<source screenshot file name when available>\"\n   }\n   ```\n\n7. Save through Cowart.\n\n   Only do Cowart state access after the bitmap is generated. Use this access only to insert the new image beside the anchor or in a nearby clear area, not to discover edit intent.\n\n   Preferred MCP call shape:\n\n   ```json\n   {\n     \"imagePath\": \"/absolute/path/to/annotation-edit-20260620-153012.png\",\n     \"projectDir\": \"/absolute/path/to/user/codex-project\",\n     \"anchorShapeId\": \"<selected source image or frame id>\",\n     \"placement\": \"right\",\n     \"margin\": 40,\n     \"matchAnchor\": true,\n     \"fileName\": \"annotation-edit-20260620-153012.png\",\n     \"annotationScreenshot\": \"<source screenshot file name when available>\",\n     \"shapeMeta\": {\n       \"cowartGeneratedFromAnnotationEdit\": true\n     },\n     \"altText\": \"Revised image generated from Cowart annotation screenshot\"\n   }\n   ```\n\n   The MCP tool must return the new `assetId`, `shapeId`, saved asset path,\n   page id, bounds, and generated `index`. Confirm that the returned `index` is\n   a valid tldraw fractional index and not a custom descriptive string.\n\n   Fallback only when `insert_cowart_image` is unavailable: update the required store snapshot and save it with `save_cowart_canvas_state`.\n\n   In fallback mode, use page-local image asset URLs:\n\n   ```text\n   /page-assets/<page-dir>/<filename>\n   ```\n\n   Cowart's MCP storage layer will preserve per-page snapshots under:\n\n   ```text\n   canvas/pages/<page-id-without-page-prefix>/cowart-canvas.json\n   ```\n\n8. Verify visually.\n\n   Let the Cowart widget refresh from MCP-backed storage, then confirm:\n\n   - the original image is still in the same place\n   - the original 批注 arrows and labels are still visible\n   - the new revised image appears beside the original\n   - the new image does not include annotation arrows, labels, selections, or UI chrome\n\n## Guardrails\n\n- Never replace the original image unless the user explicitly asks for replacement.\n- Never delete or move annotation shapes; they are the visible edit brief.\n- Never put the revised image inside the original `AI 图片` frame, because that can cover the old image and make the before/after comparison harder.\n- Never auto-capture or scan the current canvas for edit intent; use the screenshot(s) supplied by the user.\n- If the annotations contradict each other, generate the most literal combined interpretation and mention the ambiguity.\n- If a supplied screenshot shows selected-state outlines or toolbar UI, treat them as context only, not as content to generate.\n","skills/cowart-open-canvas/SKILL.md":"---\nname: cowart-open-canvas\ndescription: Open, reopen, or explicitly refresh the native Cowart canvas when the user asks to see it, or when a bare @Cowart invocation has no other requested workflow.\n---\n\n# Cowart Open Canvas\n\nThe actual canvas-opening capability is the `cowart_mcp` MCP server and its `render_cowart_canvas_widget` tool. Use this skill when the user asks to open, reopen, or explicitly refresh the canvas. A bare `@Cowart` invocation with no other actionable request may also open the canvas. Do not use this skill as a prerequisite for image generation, annotation editing, HTML, Slides, or follow-up requests sent from an already-open Cowart widget.\n\n## Workflow\n\n1. Ensure the `cowart_mcp` MCP server is loaded or discoverable and that its `render_cowart_canvas_widget` tool is available. The host may expose the complete tool name as `mcp__cowart_mcp__render_cowart_canvas_widget`. Call the tool once for the user's open, reopen, or explicit refresh request. Pass the user's active Codex workspace as `projectDir`; do not pass the Cowart plugin repository directory.\n\n```json\n{\n  \"projectDir\": \"/absolute/path/to/user/codex-project\"\n}\n```\n\nThe tool returns `openai/outputTemplate: ui://widget/cowart/canvas.html`, which tells Codex to render the widget directly. Do not start `scripts/start-canvas.sh` or open a localhost URL for normal use.\n\nCowart also declares an OpenAI MCP Extensions `global` entrypoint, so supported hosts can show it in navigation and let the user pin it. Clicking that entrypoint sends `{}` and opens the canvas directly at `<system Documents>/Cowart/canvas/`. This is one shared local canvas with multiple pages; the first page is created only when none exists. There is no project picker. Empty arguments never infer a workspace from the MCP process directory. When a workspace is known in chat, keep passing `projectDir` to open its canvas directly. Cowart declares only the `fullscreen` display mode; in a conversation, the host may place fullscreen apps in the content side panel.\n\nFor follow-ups from the global app, use the `projectDir` and `canvasDir` supplied in Cowart's model context or follow-up message. Do not substitute the global app thread's own working directory for the open canvas.\n\n2. Confirm the widget opens for the user. The canvas data is stored in the active project:\n\n```text\ncanvas/pages/<page-id>/cowart-canvas.json\ncanvas/pages/<page-id>/assets/\n```\n\n3. If the MCP tool is not visible in the current turn, use tool discovery for Cowart widget/render capabilities and retry within the same task after an explicit Cowart canvas invocation. Do not claim that a new task is required merely because one turn did not expose the tool. Only suggest a new Codex task when the plugin was just installed or upgraded and the MCP schema is still unavailable after discovery and an explicit retry.\n\n## Constraints\n\nDo not call `render_cowart_canvas_widget` again merely because another Cowart skill applies or an existing widget sends a follow-up request. The existing widget synchronizes MCP-backed canvas changes itself. Do not launch the old local web service, inspect canvas files, run builds, check storage layout, take screenshots, or perform other validation steps unless opening the widget fails or the user explicitly asks for those checks. The `scripts/start-canvas.sh` path is now only a local-development fallback.\n"},"items":[{"name":"openai.yaml","path":"skills/cowart-image-edit/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/zhongerxin/Cowart/HEAD/skills/cowart-image-edit/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: \"Cowart Image Edit\"\n  short_description: \"Generate revised images from annotated screenshots\"\n  default_prompt: \"Use $cowart:cowart-image-edit to generate revised AI images from the Cowart 批注 screenshots I provide and place each result beside its original.\"\n","isInternal":false,"tokens":61,"sizeBytes":289},{"name":"SKILL.md","path":"skills/cowart-image-edit/SKILL.md","rawUrl":"https://raw.githubusercontent.com/zhongerxin/Cowart/HEAD/skills/cowart-image-edit/SKILL.md","title":"cowart-image-edit","category":"anthropic-skill","format":"markdown","content":"---\nname: cowart-image-edit\ndescription: Generate revised AI images from user-supplied Cowart annotation screenshots and place each result beside its original without replacing, moving, hiding, or deleting existing images or annotations.\n---\n\n# Cowart Image Edit\n\nUse this skill to turn user-provided Cowart 批注 screenshots into revised AI-generated bitmaps placed next to the corresponding original images.\n\n## Preconditions\n\nEnsure the `cowart_mcp` tools required by this workflow are available. Do not call `render_cowart_canvas_widget` as a routine prerequisite: annotation requests sent from the Cowart widget already have an open canvas, and the existing widget synchronizes inserted results from MCP-backed storage. If the user separately asks to open, reopen, or explicitly refresh the canvas, handle that request once with the canvas-opening workflow.\n\nCowart state is read and written through Cowart MCP tools, not through a localhost browser service.\n\nThe user is responsible for providing the relevant screenshot(s). Do not auto-capture the current canvas and do not scan the whole canvas to infer edit requests; a canvas may contain many images with different annotations.\n\n## Workflow\n\nFor a follow-up from Cowart's sidebar canvas, use the exact `projectDir` and `canvasDir` in the Cowart context/message for all Cowart tools. These paths can differ from the conversation working directory. In ordinary project conversations, keep using the active user project as before.\n\n1. Read the user-provided screenshot(s).\n\n   Treat each screenshot as the authoritative edit brief for one output image unless the user says multiple screenshots belong to the same image.\n\n   If the user provides multiple screenshots, process them independently and keep their generated outputs separate. Do not merge annotations across screenshots unless explicitly requested.\n\n2. Extract the edit requirements from each screenshot.\n\n   Read visible 批注 labels, arrows, and nearby edit notes from the screenshot itself. Use the arrow tip or marked region to understand where each note applies.\n\n   Ignore editor chrome such as toolbars, blue selection outlines, resize handles, cursor icons, and unrelated neighboring images.\n\n3. Choose the source image for generation.\n\n   Use the clean underlying image content visible in the provided screenshot as the visual base whenever possible.\n\n   If the screenshot is too cropped, obstructed, or low-resolution to serve as a good image base, ask the user for the original image export or a cleaner screenshot of that specific image.\n\n   Do not read the current Cowart canvas to discover edit intent. Use the screenshot for the requested changes. Cowart state may be read later only to place the generated result without covering existing content.\n\n4. Prepare image-generation input.\n\n   Use the provided screenshot, plus a cleaner source image if the user supplied one.\n\n   The generation prompt should:\n\n   - apply the 批注 text as edit instructions\n   - preserve the original image's subject, composition, aspect ratio, and style unless an annotation asks otherwise\n   - remove all annotation artifacts from the output, including red arrows, labels, blue selection outlines, handles, and tool UI\n   - output only the revised clean image\n\n5. Generate a new bitmap.\n\n   Use the built-in image generation flow available in the current environment. Do not overwrite the source image file. Save the new bitmap with a timestamped filename, for example:\n\n   ```text\n   annotation-edit-20260620-153012.png\n   ```\n\n   Resolve the actual local output image carefully before inserting it into Cowart. Do not assume the built-in image generation flow always writes a fresh file under `$CODEX_HOME/generated_images`.\n\n   Preferred resolution order:\n\n   - Use the exact local image path returned by the current image generation tool call when one is available.\n   - If no new file path is returned, inspect the current Codex session JSONL for the current request and extract the PNG/base64 payload from the latest `image_generation_call.result`, then write it to the timestamped output filename.\n   - Use `$CODEX_HOME/generated_images` only when you can prove the file was created by the current request, for example by matching its timestamp after this generation step. Never pick an older image merely because it is the newest file in a stale generated_images directory.\n\n   Before inserting the resolved file into Cowart, visually inspect the local bitmap and confirm it is the newly generated revised image for this screenshot, not a stale generated asset.\n\n6. Insert the revised image beside the original with Cowart MCP.\n\n   Prefer the Cowart MCP `insert_cowart_image` tool. Do not hand-write\n   tldraw `asset` / `shape` records or fractional `index` keys unless the MCP\n   tool is unavailable. The tool copies the bitmap into the page-local assets\n   folder, creates the tldraw image asset and image shape, generates a valid\n   tldraw fractional index, places the image beside the anchor while avoiding\n   overlaps, and saves through the project-backed Cowart canvas files.\n\n   Add a new tldraw image asset and a new image shape. Do not update, remove, hide, reparent, or reorder the original image, the original `AI 图片` frame, or any annotation shapes.\n\n   Prefer a clear placement anchor when one is already available:\n\n   - If the user has selected the original image, use that image as the anchor.\n   - If the user has selected the original `AI 图片` frame, use that frame as the anchor.\n   - If the screenshot clearly shows the original image and there is a unique matching generated/original image or `AI 图片` frame on the current Cowart page, use that as the anchor without asking the user to select it.\n   - If there are multiple screenshots/outputs and the matching anchors are not uniquely identifiable, ask the user to select each corresponding anchor or provide an explicit placement order.\n   - If no anchor is clear and the user has not required a specific side-by-side comparison, place the result in a nearby clear area on the current page where it does not cover, move, hide, or delete the original image or annotations.\n\n   Placement rules:\n\n   - If the source image is inside an `AI 图片` frame, use the frame's page-level bounds as the anchor and place the new image as a sibling of that frame.\n   - Otherwise use the source image's own bounds and parent.\n   - When the annotated source appears to have earlier revision images nearby, prefer placing the new revised image to the right of the currently annotated/source image, because older annotation outputs may already live on the left.\n   - Place the new image to the right of the anchor with a margin of about `40` canvas units.\n   - Match the displayed width and height of the anchor unless the user asks for a different size.\n   - If that position would overlap existing content, keep moving right by `anchor width + 40` until the new image is clear.\n   - If using a clear-area fallback with no anchor, keep the generated image near the annotated source page, match the likely source image size when known, and choose a position that does not overlap existing shapes.\n\n   Recommended shape metadata:\n\n   ```json\n   {\n     \"cowartGeneratedFromAnnotationEdit\": true,\n     \"cowartAnnotationSourceShapeId\": \"<selected source image or frame id>\",\n     \"cowartAnnotationScreenshot\": \"<source screenshot file name when available>\"\n   }\n   ```\n\n7. Save through Cowart.\n\n   Only do Cowart state access after the bitmap is generated. Use this access only to insert the new image beside the anchor or in a nearby clear area, not to discover edit intent.\n\n   Preferred MCP call shape:\n\n   ```json\n   {\n     \"imagePath\": \"/absolute/path/to/annotation-edit-20260620-153012.png\",\n     \"projectDir\": \"/absolute/path/to/user/codex-project\",\n     \"anchorShapeId\": \"<selected source image or frame id>\",\n     \"placement\": \"right\",\n     \"margin\": 40,\n     \"matchAnchor\": true,\n     \"fileName\": \"annotation-edit-20260620-153012.png\",\n     \"annotationScreenshot\": \"<source screenshot file name when available>\",\n     \"shapeMeta\": {\n       \"cowartGeneratedFromAnnotationEdit\": true\n     },\n     \"altText\": \"Revised image generated from Cowart annotation screenshot\"\n   }\n   ```\n\n   The MCP tool must return the new `assetId`, `shapeId`, saved asset path,\n   page id, bounds, and generated `index`. Confirm that the returned `index` is\n   a valid tldraw fractional index and not a custom descriptive string.\n\n   Fallback only when `insert_cowart_image` is unavailable: update the required store snapshot and save it with `save_cowart_canvas_state`.\n\n   In fallback mode, use page-local image asset URLs:\n\n   ```text\n   /page-assets/<page-dir>/<filename>\n   ```\n\n   Cowart's MCP storage layer will preserve per-page snapshots under:\n\n   ```text\n   canvas/pages/<page-id-without-page-prefix>/cowart-canvas.json\n   ```\n\n8. Verify visually.\n\n   Let the Cowart widget refresh from MCP-backed storage, then confirm:\n\n   - the original image is still in the same place\n   - the original 批注 arrows and labels are still visible\n   - the new revised image appears beside the original\n   - the new image does not include annotation arrows, labels, selections, or UI chrome\n\n## Guardrails\n\n- Never replace the original image unless the user explicitly asks for replacement.\n- Never delete or move annotation shapes; they are the visible edit brief.\n- Never put the revised image inside the original `AI 图片` frame, because that can cover the old image and make the before/after comparison harder.\n- Never auto-capture or scan the current canvas for edit intent; use the screenshot(s) supplied by the user.\n- If the annotations contradict each other, generate the most literal combined interpretation and mention the ambiguity.\n- If a supplied screenshot shows selected-state outlines or toolbar UI, treat them as context only, not as content to generate.\n","frontmatter":{"name":"cowart-image-edit","description":"Generate revised AI images from user-supplied Cowart annotation screenshots and place each result beside its original without replacing, moving, hiding, or deleting existing images or annotations."},"isInternal":false,"tokens":2061,"sizeBytes":9947},{"name":"openai.yaml","path":"skills/cowart-image-gen/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/zhongerxin/Cowart/HEAD/skills/cowart-image-gen/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: \"Cowart Image Gen\"\n  short_description: \"Replace a selected Cowart AI holder with a generated image\"\n  default_prompt: \"Use $cowart:cowart-image-gen to replace the selected Cowart AI image holder with a generated image.\"\n\npolicy:\n  allow_implicit_invocation: true\n","isInternal":false,"tokens":68,"sizeBytes":291},{"name":"SKILL.md","path":"skills/cowart-image-gen/SKILL.md","rawUrl":"https://raw.githubusercontent.com/zhongerxin/Cowart/HEAD/skills/cowart-image-gen/SKILL.md","title":"cowart-image-gen","category":"anthropic-skill","format":"markdown","content":"---\nname: cowart-image-gen\ndescription: Generate and place a final AI bitmap on the Cowart canvas, replacing a selected AI 图片 holder or inserting the image into the current page.\n---\n\n# Cowart Image Gen\n\nUse this skill when the user wants an AI-generated image placed onto the Cowart canvas. A selected `AI 图片` holder gives a precise size and placement target, but it is not required. By default, a selected holder is a temporary target and should be replaced by the generated image.\n\n## Preconditions\n\nEnsure the `cowart_mcp` tools required by this workflow are available. Do not call `render_cowart_canvas_widget` as a routine prerequisite: requests sent from the Cowart widget already have an open canvas, and the existing widget synchronizes inserted images from MCP-backed storage. If the user separately asks to open, reopen, or explicitly refresh the canvas, handle that request once with the canvas-opening workflow.\n\nCowart state is read and written through Cowart MCP tools, not through a localhost browser service.\n\nNew holders are tldraw `frame` shapes with:\n\n```json\n{\n  \"type\": \"frame\",\n  \"meta\": {\n    \"cowartAiImageHolder\": true\n  }\n}\n```\n\nOlder canvases may still contain legacy `geo` rectangle holders with the same\nmeta flag. Support both shapes.\n\n## Workflow\n\nFor a follow-up from Cowart's sidebar canvas, use the exact `projectDir` and `canvasDir` in the Cowart context/message for all Cowart tools. These paths can differ from the conversation working directory. In ordinary project conversations, keep using the active user project as before.\n\n1. Read the selected shape from Cowart with the MCP `get_cowart_selection` tool. Pass the active user project directory as `projectDir`.\n\n2. Check whether exactly one selected shape is an AI image holder. A holder is any selected shape with either:\n\n   ```text\n   isAiImageHolder: true\n   ```\n\n   or:\n\n   ```text\n   meta.cowartAiImageHolder: true\n   ```\n\n   If yes, use the holder replacement workflow below. If not, do not ask the user to select a holder; use the standalone workflow below and insert the generated image into the current Cowart page.\n\n3. Choose the placement workflow.\n\n   Holder replacement workflow: use the selected holder's `props.w` and `props.h` as the size contract for both generation and placement. Before generating, derive and keep these values:\n\n   - `targetWidth`: selected holder `props.w`\n   - `targetHeight`: selected holder `props.h`\n   - `targetAspectRatio`: the reduced `targetWidth:targetHeight` ratio when it maps cleanly, plus the decimal `targetWidth / targetHeight`\n\n   If the selected holder matches a Cowart ratio preset such as `1:1`, `3:2`, `2:3`, `4:3`, `3:4`, `16:9`, or `9:16`, use that preset label as the human-readable aspect ratio. The generated image should be composed for this target size and aspect ratio, and should not rely on later stretching or cropping to fit the holder.\n\n   The generated image should replace the selected holder as a normal tldraw image shape:\n\n   - `parentId`: same parent as the holder\n   - `x`, `y`, `rotation`: same as the holder\n   - `props.w`, `props.h`: same as the holder\n\n   This leaves the final canvas with an image shape at the holder's position, not an AI holder that contains an image. Only preserve the holder when the user explicitly asks to keep the reusable slot.\n\n   Standalone workflow: when no AI holder is selected, generate the image anyway and insert it as a normal image shape on the current page. Prefer the current page from Cowart view state; if there is a selected non-holder shape and it is useful as context, place the image beside it, otherwise place it in a clear page area. If the user requested a size or aspect ratio, pass that size and ratio into generation and use it for display. Otherwise, use the generated bitmap's natural aspect ratio and a practical display width such as 512 canvas units.\n\n4. Generate the bitmap with the built-in `imagegen` skill unless the user explicitly requests another image path. If the requested asset needs visible copy, labels, poster text, ad text, UI text, or typography, include that text directly in the image generation prompt and let the image model produce the final bitmap. Do not default to generating a text-free background and then adding text locally unless the user explicitly asks for local typography, deterministic text overlay, SVG/vector output, or another non-imagegen layout step.\n\n   For the holder workflow, the image generation request must explicitly include the selected holder's target size and aspect ratio. Add this information to the model prompt, for example:\n\n   ```text\n   Target canvas slot: 512 x 683 canvas units.\n   Target aspect ratio: 3:4 (0.75 width/height).\n   Compose the final bitmap for this portrait ratio so it fits the slot without cropping or stretching.\n   ```\n\n   If the image generation tool or model accepts size or aspect-ratio parameters, pass the closest supported option in addition to the prompt text. If only prompt text is available, the prompt text must still include `targetWidth`, `targetHeight`, and `targetAspectRatio`.\n\n   Resolve the actual local output image carefully before inserting it into Cowart. Do not assume the built-in image generation flow always writes a fresh file under `$CODEX_HOME/generated_images`.\n\n   Preferred resolution order:\n\n   - Use the exact local image path returned by the current image generation tool call when one is available.\n   - If no new file path is returned, inspect the current Codex session JSONL for the current request and extract the PNG/base64 payload from the latest `image_generation_call.result`, then write it to a timestamped output filename.\n   - Use `$CODEX_HOME/generated_images` only when you can prove the file was created by the current request, for example by matching its timestamp after this generation step. Never pick an older image merely because it is the newest file in a stale generated_images directory.\n\n   Before inserting the resolved file into Cowart, visually inspect the local bitmap and confirm it is the newly generated image for this request, not a stale generated asset.\n\n   For project-bound output, copy the resolved generated image into the selected page's asset folder:\n\n   ```text\n   canvas/pages/<page-id-without-page-prefix>/assets/\n   ```\n\n5. Insert the generated image as a new tldraw image shape.\n\n   For the holder replacement workflow, call `insert_cowart_image` with the holder id as `anchorShapeId` and leave `replaceAiImageHolder` unset or set it to `true`. The MCP tool will place the image exactly where the holder was and remove the holder shape:\n\n   - `type`: `image`\n   - `parentId`: same as holder parent\n   - `x`, `y`, `rotation`: same as holder\n   - `props.w`, `props.h`: same as holder\n   - `props.assetId`: the new image asset id\n   - `meta.cowartGeneratedForAiImageHolder`: holder shape id\n   - `meta.cowartReplacedAiImageHolder`: `true`\n\n   If the user explicitly asks to keep the AI holder reusable, call `insert_cowart_image` with `replaceAiImageHolder: false`; for frame holders that legacy mode inserts the generated image as a child of the frame.\n\n   For the standalone workflow, insert it into the current page as a normal image:\n\n   - `type`: `image`\n   - `parentId`: current page id, unless placing beside a selected non-holder shape requires the same parent\n   - `x`, `y`: a clear page area or beside the selected non-holder shape\n   - `rotation`: `0`\n   - `props.w`, `props.h`: display size matching the generated bitmap aspect ratio\n   - `props.assetId`: the new image asset id\n   - `meta.cowartGeneratedStandalone`: `true`\n\n6. Delete the selected holder by default as part of replacement. In the standalone workflow, do not create a holder first unless the user explicitly asks for one.\n\n7. Save through Cowart MCP. Prefer `insert_cowart_image` for inserting the generated bitmap, or use `save_cowart_canvas_state` only when you must update the whole tldraw snapshot.\n\n   Prefer page-local asset URLs in the image asset:\n\n   ```text\n   /page-assets/<page-id-without-page-prefix>/<filename>\n   ```\n\n8. Let the Cowart widget refresh from MCP-backed storage, then confirm the inserted shape id, final dimensions, target aspect ratio, saved asset path, and replaced holder id when the holder replacement workflow was used.\n\n## Notes\n\n- If the holder is a legacy rotated `geo` rectangle, preserve the same `rotation` on the replacement image.\n- If there is already a generated image inside the holder from an older Cowart version, replacing the holder should remove the holder and its child image shape, then create one normal image shape in the holder's former position.\n- Do not refuse generation solely because no `AI 图片` holder is selected. Generate the bitmap and insert it into the current Cowart page.\n- Never overwrite an existing asset file; use a timestamped filename.\n","frontmatter":{"name":"cowart-image-gen","description":"Generate and place a final AI bitmap on the Cowart canvas, replacing a selected AI 图片 holder or inserting the image into the current page."},"isInternal":false,"tokens":1961,"sizeBytes":8886},{"name":"openai.yaml","path":"skills/cowart-open-canvas/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/zhongerxin/Cowart/HEAD/skills/cowart-open-canvas/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: \"Cowart Open Canvas\"\n  short_description: \"Open the Cowart infinite-canvas widget\"\n  default_prompt: \"Use $cowart:cowart-open-canvas to open the Cowart infinite-canvas widget.\"\n","isInternal":false,"tokens":51,"sizeBytes":204},{"name":"SKILL.md","path":"skills/cowart-open-canvas/SKILL.md","rawUrl":"https://raw.githubusercontent.com/zhongerxin/Cowart/HEAD/skills/cowart-open-canvas/SKILL.md","title":"cowart-open-canvas","category":"anthropic-skill","format":"markdown","content":"---\nname: cowart-open-canvas\ndescription: Open, reopen, or explicitly refresh the native Cowart canvas when the user asks to see it, or when a bare @Cowart invocation has no other requested workflow.\n---\n\n# Cowart Open Canvas\n\nThe actual canvas-opening capability is the `cowart_mcp` MCP server and its `render_cowart_canvas_widget` tool. Use this skill when the user asks to open, reopen, or explicitly refresh the canvas. A bare `@Cowart` invocation with no other actionable request may also open the canvas. Do not use this skill as a prerequisite for image generation, annotation editing, HTML, Slides, or follow-up requests sent from an already-open Cowart widget.\n\n## Workflow\n\n1. Ensure the `cowart_mcp` MCP server is loaded or discoverable and that its `render_cowart_canvas_widget` tool is available. The host may expose the complete tool name as `mcp__cowart_mcp__render_cowart_canvas_widget`. Call the tool once for the user's open, reopen, or explicit refresh request. Pass the user's active Codex workspace as `projectDir`; do not pass the Cowart plugin repository directory.\n\n```json\n{\n  \"projectDir\": \"/absolute/path/to/user/codex-project\"\n}\n```\n\nThe tool returns `openai/outputTemplate: ui://widget/cowart/canvas.html`, which tells Codex to render the widget directly. Do not start `scripts/start-canvas.sh` or open a localhost URL for normal use.\n\nCowart also declares an OpenAI MCP Extensions `global` entrypoint, so supported hosts can show it in navigation and let the user pin it. Clicking that entrypoint sends `{}` and opens the canvas directly at `<system Documents>/Cowart/canvas/`. This is one shared local canvas with multiple pages; the first page is created only when none exists. There is no project picker. Empty arguments never infer a workspace from the MCP process directory. When a workspace is known in chat, keep passing `projectDir` to open its canvas directly. Cowart declares only the `fullscreen` display mode; in a conversation, the host may place fullscreen apps in the content side panel.\n\nFor follow-ups from the global app, use the `projectDir` and `canvasDir` supplied in Cowart's model context or follow-up message. Do not substitute the global app thread's own working directory for the open canvas.\n\n2. Confirm the widget opens for the user. The canvas data is stored in the active project:\n\n```text\ncanvas/pages/<page-id>/cowart-canvas.json\ncanvas/pages/<page-id>/assets/\n```\n\n3. If the MCP tool is not visible in the current turn, use tool discovery for Cowart widget/render capabilities and retry within the same task after an explicit Cowart canvas invocation. Do not claim that a new task is required merely because one turn did not expose the tool. Only suggest a new Codex task when the plugin was just installed or upgraded and the MCP schema is still unavailable after discovery and an explicit retry.\n\n## Constraints\n\nDo not call `render_cowart_canvas_widget` again merely because another Cowart skill applies or an existing widget sends a follow-up request. The existing widget synchronizes MCP-backed canvas changes itself. Do not launch the old local web service, inspect canvas files, run builds, check storage layout, take screenshots, or perform other validation steps unless opening the widget fails or the user explicitly asks for those checks. The `scripts/start-canvas.sh` path is now only a local-development fallback.\n","frontmatter":{"name":"cowart-open-canvas","description":"Open, reopen, or explicitly refresh the native Cowart canvas when the user asks to see it, or when a bare @Cowart invocation has no other requested workflow."},"isInternal":false,"tokens":737,"sizeBytes":3390},{"name":"marketplace.json","path":".agents/plugins/marketplace.json","rawUrl":"https://raw.githubusercontent.com/zhongerxin/Cowart/HEAD/.agents/plugins/marketplace.json","title":"cowart-github","category":"marketplace","format":"json","content":"{\n  \"name\": \"cowart-github\",\n  \"interface\": {\n    \"displayName\": \"Cowart GitHub\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"cowart\",\n      \"source\": {\n        \"source\": \"local\",\n        \"path\": \".\"\n      },\n      \"policy\": {\n        \"installation\": \"AVAILABLE\",\n        \"authentication\": \"ON_INSTALL\"\n      },\n      \"category\": \"Productivity\"\n    }\n  ]\n}\n","frontmatter":{"name":"cowart-github","interface":{"displayName":"Cowart GitHub"},"plugins":[{"name":"cowart","source":{"source":"local","path":"."},"policy":{"installation":"AVAILABLE","authentication":"ON_INSTALL"},"category":"Productivity"}]},"isInternal":false,"tokens":97,"sizeBytes":353},{"name":"plugin.json","path":".codex-plugin/plugin.json","rawUrl":"https://raw.githubusercontent.com/zhongerxin/Cowart/HEAD/.codex-plugin/plugin.json","title":"cowart","category":"plugin-manifest","format":"json","content":"{\n  \"name\": \"cowart\",\n  \"version\": \"0.1.38\",\n  \"description\": \"A native fullscreen tldraw canvas for images, HTML, Slides and AI motion films. Open the canvas with Cowart MCP and reuse it for generation and playback.\",\n  \"author\": {\n    \"name\": \"ZHONG XIN\",\n    \"email\": \"zhongxin123456@gmail.com\",\n    \"url\": \"https://www.jiqiren.ai\"\n  },\n  \"homepage\": \"https://www.jiqiren.ai\",\n  \"repository\": \"https://github.com/zhongerxin/Cowart\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"canvas\",\n    \"tldraw\",\n    \"whiteboard\",\n    \"image-generation\",\n    \"visual-collaboration\"\n  ],\n  \"skills\": \"./skills/\",\n  \"mcpServers\": \"./.mcp.json\",\n  \"interface\": {\n    \"displayName\": \"Cowart\",\n    \"shortDescription\": \"Your fullscreen project canvas\",\n    \"longDescription\": \"Cowart brings a native tldraw canvas into Codex for visual planning and creative iteration. Open Cowart from global navigation and pin it with the host pin control. The sidebar opens a single canvas in the system Documents/Cowart folder, creating the first page when needed. Project conversations with projectDir keep their own project canvas. Image, HTML, Slides, AI film and annotation workflows reuse the open canvas.\",\n    \"developerName\": \"ZHONG XIN\",\n    \"category\": \"Productivity\",\n    \"websiteURL\": \"https://www.jiqiren.ai\",\n    \"brandColor\": \"#25BFEF\",\n    \"logo\": \"./assets/app-icon.png\",\n    \"composerIcon\": \"./assets/app-icon.png\",\n    \"capabilities\": [\n      \"Fullscreen canvas\",\n      \"Sidebar entrypoint\",\n      \"AI image generation\",\n      \"Annotation-driven editing\",\n      \"Project-local persistence\",\n      \"AI motion films with playback\"\n    ],\n    \"defaultPrompt\": [\n      \"Open the Cowart canvas for this project.\",\n      \"Use my Cowart annotation screenshot to generate a clean revised image beside the original.\",\n      \"Generate a new image into the selected Cowart AI image holder.\",\n      \"Generate an AI motion film into the selected Cowart film holder using cowart-film-gen.\"\n    ]\n  }\n}\n","frontmatter":{"name":"cowart","version":"0.1.38","description":"A native fullscreen tldraw canvas for images, HTML, Slides and AI motion films. Open the canvas with Cowart MCP and reuse it for generation and playback.","author":{"name":"ZHONG XIN","email":"zhongxin123456@gmail.com","url":"https://www.jiqiren.ai"},"homepage":"https://www.jiqiren.ai","repository":"https://github.com/zhongerxin/Cowart","license":"MIT","keywords":["canvas","tldraw","whiteboard","image-generation","visual-collaboration"],"skills":"./skills/","mcpServers":"./.mcp.json","interface":{"displayName":"Cowart","shortDescription":"Your fullscreen project canvas","longDescription":"Cowart brings a native tldraw canvas into Codex for visual planning and creative iteration. Open Cowart from global navigation and pin it with the host pin control. The sidebar opens a single canvas in the system Documents/Cowart folder, creating the first page when needed. Project conversations with projectDir keep their own project canvas. Image, HTML, Slides, AI film and annotation workflows reuse the open canvas.","developerName":"ZHONG XIN","category":"Productivity","websiteURL":"https://www.jiqiren.ai","brandColor":"#25BFEF","logo":"./assets/app-icon.png","composerIcon":"./assets/app-icon.png","capabilities":["Fullscreen canvas","Sidebar entrypoint","AI image generation","Annotation-driven editing","Project-local persistence","AI motion films with playback"],"defaultPrompt":["Open the Cowart canvas for this project.","Use my Cowart annotation screenshot to generate a clean revised image beside the original.","Generate a new image into the selected Cowart AI image holder.","Generate an AI motion film into the selected Cowart film holder using cowart-film-gen."]}},"isInternal":false,"tokens":493,"sizeBytes":1975},{"name":"plugin.json","path":"plugin.json","rawUrl":"https://raw.githubusercontent.com/zhongerxin/Cowart/HEAD/plugin.json","title":"cowart","category":"plugin-manifest","format":"json","content":"{\n  \"$schema\": \"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json\",\n  \"name\": \"cowart\",\n  \"version\": \"0.1.38\",\n  \"description\": \"A native fullscreen tldraw canvas for images, HTML, Slides and AI motion films. Open the canvas with Cowart MCP and reuse it for generation and playback.\",\n  \"author\": {\n    \"name\": \"ZHONG XIN\",\n    \"email\": \"zhongxin123456@gmail.com\",\n    \"url\": \"https://www.jiqiren.ai\"\n  },\n  \"homepage\": \"https://www.jiqiren.ai\",\n  \"repository\": \"https://github.com/zhongerxin/Cowart\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"canvas\",\n    \"tldraw\",\n    \"whiteboard\",\n    \"image-generation\",\n    \"visual-collaboration\"\n  ],\n  \"extensions\": {\n    \"com.openai\": {\n      \"interface\": {\n        \"displayName\": \"Cowart\",\n        \"shortDescription\": \"Your fullscreen project canvas\",\n        \"longDescription\": \"Cowart brings a native tldraw canvas into Codex for visual planning and creative iteration. Open Cowart from global navigation and pin it with the host pin control. The sidebar opens a single canvas in the system Documents/Cowart folder, creating the first page when needed. Project conversations with projectDir keep their own project canvas. Image, HTML, Slides, AI film and annotation workflows reuse the open canvas.\",\n        \"developerName\": \"ZHONG XIN\",\n        \"category\": \"Productivity\",\n        \"websiteURL\": \"https://www.jiqiren.ai\",\n        \"brandColor\": \"#25BFEF\",\n        \"logo\": \"./assets/app-icon.png\",\n        \"composerIcon\": \"./assets/app-icon.png\",\n        \"capabilities\": [\n          \"Fullscreen canvas\",\n          \"Sidebar entrypoint\",\n          \"AI image generation\",\n          \"Annotation-driven editing\",\n          \"Project-local persistence\",\n          \"AI motion films with playback\"\n        ],\n        \"defaultPrompt\": [\n          \"Open the Cowart canvas for this project.\",\n          \"Use my Cowart annotation screenshot to generate a clean revised image beside the original.\",\n          \"Generate a new image into the selected Cowart AI image holder.\",\n          \"Generate an AI motion film into the selected Cowart film holder using cowart-film-gen.\"\n        ]\n      }\n    }\n  }\n}\n","frontmatter":{"$schema":"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json","name":"cowart","version":"0.1.38","description":"A native fullscreen tldraw canvas for images, HTML, Slides and AI motion films. Open the canvas with Cowart MCP and reuse it for generation and playback.","author":{"name":"ZHONG XIN","email":"zhongxin123456@gmail.com","url":"https://www.jiqiren.ai"},"homepage":"https://www.jiqiren.ai","repository":"https://github.com/zhongerxin/Cowart","license":"MIT","keywords":["canvas","tldraw","whiteboard","image-generation","visual-collaboration"],"extensions":{"com.openai":{"interface":{"displayName":"Cowart","shortDescription":"Your fullscreen project canvas","longDescription":"Cowart brings a native tldraw canvas into Codex for visual planning and creative iteration. Open Cowart from global navigation and pin it with the host pin control. The sidebar opens a single canvas in the system Documents/Cowart folder, creating the first page when needed. Project conversations with projectDir keep their own project canvas. Image, HTML, Slides, AI film and annotation workflows reuse the open canvas.","developerName":"ZHONG XIN","category":"Productivity","websiteURL":"https://www.jiqiren.ai","brandColor":"#25BFEF","logo":"./assets/app-icon.png","composerIcon":"./assets/app-icon.png","capabilities":["Fullscreen canvas","Sidebar entrypoint","AI image generation","Annotation-driven editing","Project-local persistence","AI motion films with playback"],"defaultPrompt":["Open the Cowart canvas for this project.","Use my Cowart annotation screenshot to generate a clean revised image beside the original.","Generate a new image into the selected Cowart AI image holder.","Generate an AI motion film into the selected Cowart film holder using cowart-film-gen."]}}}},"isInternal":false,"tokens":512,"sizeBytes":2142},{"name":"mcp.json","path":"mcp.json","rawUrl":"https://raw.githubusercontent.com/zhongerxin/Cowart/HEAD/mcp.json","title":"Model Context Protocol (MCP) Configuration","category":"mcp-config","format":"json","content":"{\n  \"$schema\": \"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json\",\n  \"mcpServers\": {\n    \"cowart_mcp\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\n        \"./scripts/start-mcp.mjs\"\n      ],\n      \"cwd\": \"./\"\n    }\n  }\n}\n","frontmatter":{"$schema":"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json","mcpServers":{"cowart_mcp":{"type":"stdio","command":"node","args":["./scripts/start-mcp.mjs"],"cwd":"./"}}},"isInternal":false,"tokens":80,"sizeBytes":249}],"systemPromptSnippet":"<yakaai_skills repo=\"zhongerxin/Cowart\">\n<!-- File: skills/cowart-image-edit/agents/openai.yaml (Tokens: ~61 | Category: anthropic-skill) -->\ninterface:\n  display_name: \"Cowart Image Edit\"\n  short_description: \"Generate revised images from annotated screenshots\"\n  default_prompt: \"Use $cowart:cowart-image-edit to generate revised AI images from the Cowart 批注 screenshots I provide and place each result beside its original.\"\n\n<!-- File: skills/cowart-image-edit/SKILL.md (Tokens: ~2061 | Category: anthropic-skill) -->\n---\nname: cowart-image-edit\ndescription: Generate revised AI images from user-supplied Cowart annotation screenshots and place each result beside its original without replacing, moving, hiding, or deleting existing images or annotations.\n---\n\n# Cowart Image Edit\n\nUse this skill to turn user-provided Cowart 批注 screenshots into revised AI-generated bitmaps placed next to the corresponding original images.\n\n## Preconditions\n\nEnsure the `cowart_mcp` tools required by this workflow are available. Do not call `render_cowart_canvas_widget` as a routine prerequisite: annotation requests sent from the Cowart widget already have an open canvas, and the existing widget synchronizes inserted results from MCP-backed storage. If the user separately asks to open, reopen, or explicitly refresh the canvas, handle that request once with the canvas-opening workflow.\n\nCowart state is read and written through Cowart MCP tools, not through a localhost browser service.\n\nThe user is responsible for providing the relevant screenshot(s). Do not auto-capture the current canvas and do not scan the whole canvas to infer edit requests; a canvas may contain many images with different annotations.\n\n## Workflow\n\nFor a follow-up from Cowart's sidebar canvas, use the exact `projectDir` and `canvasDir` in the Cowart context/message for all Cowart tools. These paths can differ from the conversation working directory. In ordinary project conversations, keep using the active user project as before.\n\n1. Read the user-provided screenshot(s).\n\n   Treat each screenshot as the authoritative edit brief for one output image unless the user says multiple screenshots belong to the same image.\n\n   If the user provides multiple screenshots, process them independently and keep their generated outputs separate. Do not merge annotations across screenshots unless explicitly requested.\n\n2. Extract the edit requirements from each screenshot.\n\n   Read visible 批注 labels, arrows, and nearby edit notes from the screenshot itself. Use the arrow tip or marked region to understand where each note applies.\n\n   Ignore editor chrome such as toolbars, blue selection outlines, resize handles, cursor icons, and unrelated neighboring images.\n\n3. Choose the source image for generation.\n\n   Use the clean underlying image content visible in the provided screenshot as the visual base whenever possible.\n\n   If the screenshot is too cropped, obstructed, or low-resolution to serve as a good image base, ask the user for the original image export or a cleaner screenshot of that specific image.\n\n   Do not read the current Cowart canvas to discover edit intent. Use the screenshot for the requested changes. Cowart state may be read later only to place the generated result without covering existing content.\n\n4. Prepare image-generation input.\n\n   Use the provided screenshot, plus a cleaner source image if the user supplied one.\n\n   The generation prompt should:\n\n   - apply the 批注 text as edit instructions\n   - preserve the original image's subject, composition, aspect ratio, and style unless an annotation asks otherwise\n   - remove all annotation artifacts from the output, including red arrows, labels, blue selection outlines, handles, and tool UI\n   - output only the revised clean image\n\n5. Generate a new bitmap.\n\n   Use the built-in image generation flow available in the current environment. Do not overwrite the source image file. Save the new bitmap with a timestamped filename, for example:\n\n   ```text\n   annotation-edit-20260620-153012.png\n   ```\n\n   Resolve the actual local output image carefully before inserting it into Cowart. Do not assume the built-in image generation flow always writes a fresh file under `$CODEX_HOME/generated_images`.\n\n   Preferred resolution order:\n\n   - Use the exact local image path returned by the current image generation tool call when one is available.\n   - If no new file path is returned, inspect the current Codex session JSONL for the current request and extract the PNG/base64 payload from the latest `image_generation_call.result`, then write it to the timestamped output filename.\n   - Use `$CODEX_HOME/generated_images` only when you can prove the file was created by the current request, for example by matching its timestamp after this generation step. Never pick an older image merely because it is the newest file in a stale generated_images directory.\n\n   Before inserting the resolved file into Cowart, visually inspect the local bitmap and confirm it is the newly generated revised image for this screenshot, not a stale generated asset.\n\n6. Insert the revised image beside the original with Cowart MCP.\n\n   Prefer the Cowart MCP `insert_cowart_image` tool. Do not hand-write\n   tldraw `asset` / `shape` records or fractional `index` keys unless the MCP\n   tool is unavailable. The tool copies the bitmap into the page-local assets\n   folder, creates the tldraw image asset and image shape, generates a valid\n   tldraw fractional index, places the image beside the anchor while avoiding\n   overlaps, and saves through the project-backed Cowart canvas files.\n\n   Add a new tldraw image asset and a new image shape. Do not update, remove, hide, reparent, or reorder the original image, the original `AI 图片` frame, or any annotation shapes.\n\n   Prefer a clear placement anchor when one is already available:\n\n   - If the user has selected the original image, use that image as the anchor.\n   - If the user has selected the original `AI 图片` frame, use that frame as the anchor.\n   - If the screenshot clearly shows the original image and there is a unique matching generated/original image or `AI 图片` frame on the current Cowart page, use that as the anchor without asking the user to select it.\n   - If there are multiple screenshots/outputs and the matching anchors are not uniquely identifiable, ask the user to select each corresponding anchor or provide an explicit placement order.\n   - If no anchor is clear and the user has not required a specific side-by-side comparison, place the result in a nearby clear area on the current page where it does not cover, move, hide, or delete the original image or annotations.\n\n   Placement rules:\n\n   - If the source image is inside an `AI 图片` frame, use the frame's page-level bounds as the anchor and place the new image as a sibling of that frame.\n   - Otherwise use the source image's own bounds and parent.\n   - When the annotated source appears to have earlier revision images nearby, prefer placing the new revised image to the right of the currently annotated/source image, because older annotation outputs may already live on the left.\n   - Place the new image to the right of the anchor with a margin of about `40` canvas units.\n   - Match the displayed width and height of the anchor unless the user asks for a different size.\n   - If that position would overlap existing content, keep moving right by `anchor width + 40` until the new image is clear.\n   - If using a clear-area fallback with no anchor, keep the generated image near the annotated source page, match the likely source image size when known, and choose a position that does not overlap existing shapes.\n\n   Recommended shape metadata:\n\n   ```json\n   {\n     \"cowartGeneratedFromAnnotationEdit\": true,\n     \"cowartAnnotationSourceShapeId\": \"<selected source image or frame id>\",\n     \"cowartAnnotationScreenshot\": \"<source screenshot file name when available>\"\n   }\n   ```\n\n7. Save through Cowart.\n\n   Only do Cowart state access after the bitmap is generated. Use this access only to insert the new image beside the anchor or in a nearby clear area, not to discover edit intent.\n\n   Preferred MCP call shape:\n\n   ```json\n   {\n     \"imagePath\": \"/absolute/path/to/annotation-edit-20260620-153012.png\",\n     \"projectDir\": \"/absolute/path/to/user/codex-project\",\n     \"anchorShapeId\": \"<selected source image or frame id>\",\n     \"placement\": \"right\",\n     \"margin\": 40,\n     \"matchAnchor\": true,\n     \"fileName\": \"annotation-edit-20260620-153012.png\",\n     \"annotationScreenshot\": \"<source screenshot file name when available>\",\n     \"shapeMeta\": {\n       \"cowartGeneratedFromAnnotationEdit\": true\n     },\n     \"altText\": \"Revised image generated from Cowart annotation screenshot\"\n   }\n   ```\n\n   The MCP tool must return the new `assetId`, `shapeId`, saved asset path,\n   page id, bounds, and generated `index`. Confirm that the returned `index` is\n   a valid tldraw fractional index and not a custom descriptive string.\n\n   Fallback only when `insert_cowart_image` is unavailable: update the required store snapshot and save it with `save_cowart_canvas_state`.\n\n   In fallback mode, use page-local image asset URLs:\n\n   ```text\n   /page-assets/<page-dir>/<filename>\n   ```\n\n   Cowart's MCP storage layer will preserve per-page snapshots under:\n\n   ```text\n   canvas/pages/<page-id-without-page-prefix>/cowart-canvas.json\n   ```\n\n8. Verify visually.\n\n   Let the Cowart widget refresh from MCP-backed storage, then confirm:\n\n   - the original image is still in the same place\n   - the original 批注 arrows and labels are still visible\n   - the new revised image appears beside the original\n   - the new image does not include annotation arrows, labels, selections, or UI chrome\n\n## Guardrails\n\n- Never replace the original image unless the user explicitly asks for replacement.\n- Never delete or move annotation shapes; they are the visible edit brief.\n- Never put the revised image inside the original `AI 图片` frame, because that can cover the old image and make the before/after comparison harder.\n- Never auto-capture or scan the current canvas for edit intent; use the screenshot(s) supplied by the user.\n- If the annotations contradict each other, generate the most literal combined interpretation and mention the ambiguity.\n- If a supplied screenshot shows selected-state outlines or toolbar UI, treat them as context only, not as content to generate.\n\n<!-- File: skills/cowart-image-gen/agents/openai.yaml (Tokens: ~68 | Category: anthropic-skill) -->\ninterface:\n  display_name: \"Cowart Image Gen\"\n  short_description: \"Replace a selected Cowart AI holder with a generated image\"\n  default_prompt: \"Use $cowart:cowart-image-gen to replace the selected Cowart AI image holder with a generated image.\"\n\npolicy:\n  allow_implicit_invocation: true\n\n<!-- File: skills/cowart-image-gen/SKILL.md (Tokens: ~1961 | Category: anthropic-skill) -->\n---\nname: cowart-image-gen\ndescription: Generate and place a final AI bitmap on the Cowart canvas, replacing a selected AI 图片 holder or inserting the image into the current page.\n---\n\n# Cowart Image Gen\n\nUse this skill when the user wants an AI-generated image placed onto the Cowart canvas. A selected `AI 图片` holder gives a precise size and placement target, but it is not required. By default, a selected holder is a temporary target and should be replaced by the generated image.\n\n## Preconditions\n\nEnsure the `cowart_mcp` tools required by this workflow are available. Do not call `render_cowart_canvas_widget` as a routine prerequisite: requests sent from the Cowart widget already have an open canvas, and the existing widget synchronizes inserted images from MCP-backed storage. If the user separately asks to open, reopen, or explicitly refresh the canvas, handle that request once with the canvas-opening workflow.\n\nCowart state is read and written through Cowart MCP tools, not through a localhost browser service.\n\nNew holders are tldraw `frame` shapes with:\n\n```json\n{\n  \"type\": \"frame\",\n  \"meta\": {\n    \"cowartAiImageHolder\": true\n  }\n}\n```\n\nOlder canvases may still contain legacy `geo` rectangle holders with the same\nmeta flag. Support both shapes.\n\n## Workflow\n\nFor a follow-up from Cowart's sidebar canvas, use the exact `projectDir` and `canvasDir` in the Cowart context/message for all Cowart tools. These paths can differ from the conversation working directory. In ordinary project conversations, keep using the active user project as before.\n\n1. Read the selected shape from Cowart with the MCP `get_cowart_selection` tool. Pass the active user project directory as `projectDir`.\n\n2. Check whether exactly one selected shape is an AI image holder. A holder is any selected shape with either:\n\n   ```text\n   isAiImageHolder: true\n   ```\n\n   or:\n\n   ```text\n   meta.cowartAiImageHolder: true\n   ```\n\n   If yes, use the holder replacement workflow below. If not, do not ask the user to select a holder; use the standalone workflow below and insert the generated image into the current Cowart page.\n\n3. Choose the placement workflow.\n\n   Holder replacement workflow: use the selected holder's `props.w` and `props.h` as the size contract for both generation and placement. Before generating, derive and keep these values:\n\n   - `targetWidth`: selected holder `props.w`\n   - `targetHeight`: selected holder `props.h`\n   - `targetAspectRatio`: the reduced `targetWidth:targetHeight` ratio when it maps cleanly, plus the decimal `targetWidth / targetHeight`\n\n   If the selected holder matches a Cowart ratio preset such as `1:1`, `3:2`, `2:3`, `4:3`, `3:4`, `16:9`, or `9:16`, use that preset label as the human-readable aspect ratio. The generated image should be composed for this target size and aspect ratio, and should not rely on later stretching or cropping to fit the holder.\n\n   The generated image should replace the selected holder as a normal tldraw image shape:\n\n   - `parentId`: same parent as the holder\n   - `x`, `y`, `rotation`: same as the holder\n   - `props.w`, `props.h`: same as the holder\n\n   This leaves the final canvas with an image shape at the holder's position, not an AI holder that contains an image. Only preserve the holder when the user explicitly asks to keep the reusable slot.\n\n   Standalone workflow: when no AI holder is selected, generate the image anyway and insert it as a normal image shape on the current page. Prefer the current page from Cowart view state; if there is a selected non-holder shape and it is useful as context, place the image beside it, otherwise place it in a clear page area. If the user requested a size or aspect ratio, pass that size and ratio into generation and use it for display. Otherwise, use the generated bitmap's natural aspect ratio and a practical display width such as 512 canvas units.\n\n4. Generate the bitmap with the built-in `imagegen` skill unless the user explicitly requests another image path. If the requested asset needs visible copy, labels, poster text, ad text, UI text, or typography, include that text directly in the image generation prompt and let the image model produce the final bitmap. Do not default to generating a text-free background and then adding text locally unless the user explicitly asks for local typography, deterministic text overlay, SVG/vector output, or another non-imagegen layout step.\n\n   For the holder workflow, the image generation request must explicitly include the selected holder's target size and aspect ratio. Add this information to the model prompt, for example:\n\n   ```text\n   Target canvas slot: 512 x 683 canvas units.\n   Target aspect ratio: 3:4 (0.75 width/height).\n   Compose the final bitmap for this portrait ratio so it fits the slot without cropping or stretching.\n   ```\n\n   If the image generation tool or model accepts size or aspect-ratio parameters, pass the closest supported option in addition to the prompt text. If only prompt text is available, the prompt text must still include `targetWidth`, `targetHeight`, and `targetAspectRatio`.\n\n   Resolve the actual local output image carefully before inserting it into Cowart. Do not assume the built-in image generation flow always writes a fresh file under `$CODEX_HOME/generated_images`.\n\n   Preferred resolution order:\n\n   - Use the exact local image path returned by the current image generation tool call when one is available.\n   - If no new file path is returned, inspect the current Codex session JSONL for the current request and extract the PNG/base64 payload from the latest `image_generation_call.result`, then write it to a timestamped output filename.\n   - Use `$CODEX_HOME/generated_images` only when you can prove the file was created by the current request, for example by matching its timestamp after this generation step. Never pick an older image merely because it is the newest file in a stale generated_images directory.\n\n   Before inserting the resolved file into Cowart, visually inspect the local bitmap and confirm it is the newly generated image for this request, not a stale generated asset.\n\n   For project-bound output, copy the resolved generated image into the selected page's asset folder:\n\n   ```text\n   canvas/pages/<page-id-without-page-prefix>/assets/\n   ```\n\n5. Insert the generated image as a new tldraw image shape.\n\n   For the holder replacement workflow, call `insert_cowart_image` with the holder id as `anchorShapeId` and leave `replaceAiImageHolder` unset or set it to `true`. The MCP tool will place the image exactly where the holder was and remove the holder shape:\n\n   - `type`: `image`\n   - `parentId`: same as holder parent\n   - `x`, `y`, `rotation`: same as holder\n   - `props.w`, `props.h`: same as holder\n   - `props.assetId`: the new image asset id\n   - `meta.cowartGeneratedForAiImageHolder`: holder shape id\n   - `meta.cowartReplacedAiImageHolder`: `true`\n\n   If the user explicitly asks to keep the AI holder reusable, call `insert_cowart_image` with `replaceAiImageHolder: false`; for frame holders that legacy mode inserts the generated image as a child of the frame.\n\n   For the standalone workflow, insert it into the current page as a normal image:\n\n   - `type`: `image`\n   - `parentId`: current page id, unless placing beside a selected non-holder shape requires the same parent\n   - `x`, `y`: a clear page area or beside the selected non-holder shape\n   - `rotation`: `0`\n   - `props.w`, `props.h`: display size matching the generated bitmap aspect ratio\n   - `props.assetId`: the new image asset id\n   - `meta.cowartGeneratedStandalone`: `true`\n\n6. Delete the selected holder by default as part of replacement. In the standalone workflow, do not create a holder first unless the user explicitly asks for one.\n\n7. Save through Cowart MCP. Prefer `insert_cowart_image` for inserting the generated bitmap, or use `save_cowart_canvas_state` only when you must update the whole tldraw snapshot.\n\n   Prefer page-local asset URLs in the image asset:\n\n   ```text\n   /page-assets/<page-id-without-page-prefix>/<filename>\n   ```\n\n8. Let the Cowart widget refresh from MCP-backed storage, then confirm the inserted shape id, final dimensions, target aspect ratio, saved asset path, and replaced holder id when the holder replacement workflow was used.\n\n## Notes\n\n- If the holder is a legacy rotated `geo` rectangle, preserve the same `rotation` on the replacement image.\n- If there is already a generated image inside the holder from an older Cowart version, replacing the holder should remove the holder and its child image shape, then create one normal image shape in the holder's former position.\n- Do not refuse generation solely because no `AI 图片` holder is selected. Generate the bitmap and insert it into the current Cowart page.\n- Never overwrite an existing asset file; use a timestamped filename.\n\n<!-- File: skills/cowart-open-canvas/agents/openai.yaml (Tokens: ~51 | Category: anthropic-skill) -->\ninterface:\n  display_name: \"Cowart Open Canvas\"\n  short_description: \"Open the Cowart infinite-canvas widget\"\n  default_prompt: \"Use $cowart:cowart-open-canvas to open the Cowart infinite-canvas widget.\"\n\n<!-- File: skills/cowart-open-canvas/SKILL.md (Tokens: ~737 | Category: anthropic-skill) -->\n---\nname: cowart-open-canvas\ndescription: Open, reopen, or explicitly refresh the native Cowart canvas when the user asks to see it, or when a bare @Cowart invocation has no other requested workflow.\n---\n\n# Cowart Open Canvas\n\nThe actual canvas-opening capability is the `cowart_mcp` MCP server and its `render_cowart_canvas_widget` tool. Use this skill when the user asks to open, reopen, or explicitly refresh the canvas. A bare `@Cowart` invocation with no other actionable request may also open the canvas. Do not use this skill as a prerequisite for image generation, annotation editing, HTML, Slides, or follow-up requests sent from an already-open Cowart widget.\n\n## Workflow\n\n1. Ensure the `cowart_mcp` MCP server is loaded or discoverable and that its `render_cowart_canvas_widget` tool is available. The host may expose the complete tool name as `mcp__cowart_mcp__render_cowart_canvas_widget`. Call the tool once for the user's open, reopen, or explicit refresh request. Pass the user's active Codex workspace as `projectDir`; do not pass the Cowart plugin repository directory.\n\n```json\n{\n  \"projectDir\": \"/absolute/path/to/user/codex-project\"\n}\n```\n\nThe tool returns `openai/outputTemplate: ui://widget/cowart/canvas.html`, which tells Codex to render the widget directly. Do not start `scripts/start-canvas.sh` or open a localhost URL for normal use.\n\nCowart also declares an OpenAI MCP Extensions `global` entrypoint, so supported hosts can show it in navigation and let the user pin it. Clicking that entrypoint sends `{}` and opens the canvas directly at `<system Documents>/Cowart/canvas/`. This is one shared local canvas with multiple pages; the first page is created only when none exists. There is no project picker. Empty arguments never infer a workspace from the MCP process directory. When a workspace is known in chat, keep passing `projectDir` to open its canvas directly. Cowart declares only the `fullscreen` display mode; in a conversation, the host may place fullscreen apps in the content side panel.\n\nFor follow-ups from the global app, use the `projectDir` and `canvasDir` supplied in Cowart's model context or follow-up message. Do not substitute the global app thread's own working directory for the open canvas.\n\n2. Confirm the widget opens for the user. The canvas data is stored in the active project:\n\n```text\ncanvas/pages/<page-id>/cowart-canvas.json\ncanvas/pages/<page-id>/assets/\n```\n\n3. If the MCP tool is not visible in the current turn, use tool discovery for Cowart widget/render capabilities and retry within the same task after an explicit Cowart canvas invocation. Do not claim that a new task is required merely because one turn did not expose the tool. Only suggest a new Codex task when the plugin was just installed or upgraded and the MCP schema is still unavailable after discovery and an explicit retry.\n\n## Constraints\n\nDo not call `render_cowart_canvas_widget` again merely because another Cowart skill applies or an existing widget sends a follow-up request. The existing widget synchronizes MCP-backed canvas changes itself. Do not launch the old local web service, inspect canvas files, run builds, check storage layout, take screenshots, or perform other validation steps unless opening the widget fails or the user explicitly asks for those checks. The `scripts/start-canvas.sh` path is now only a local-development fallback.\n\n<!-- File: .agents/plugins/marketplace.json (Tokens: ~97 | Category: marketplace) -->\n{\n  \"name\": \"cowart-github\",\n  \"interface\": {\n    \"displayName\": \"Cowart GitHub\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"cowart\",\n      \"source\": {\n        \"source\": \"local\",\n        \"path\": \".\"\n      },\n      \"policy\": {\n        \"installation\": \"AVAILABLE\",\n        \"authentication\": \"ON_INSTALL\"\n      },\n      \"category\": \"Productivity\"\n    }\n  ]\n}\n\n<!-- File: .codex-plugin/plugin.json (Tokens: ~493 | Category: plugin-manifest) -->\n{\n  \"name\": \"cowart\",\n  \"version\": \"0.1.38\",\n  \"description\": \"A native fullscreen tldraw canvas for images, HTML, Slides and AI motion films. Open the canvas with Cowart MCP and reuse it for generation and playback.\",\n  \"author\": {\n    \"name\": \"ZHONG XIN\",\n    \"email\": \"zhongxin123456@gmail.com\",\n    \"url\": \"https://www.jiqiren.ai\"\n  },\n  \"homepage\": \"https://www.jiqiren.ai\",\n  \"repository\": \"https://github.com/zhongerxin/Cowart\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"canvas\",\n    \"tldraw\",\n    \"whiteboard\",\n    \"image-generation\",\n    \"visual-collaboration\"\n  ],\n  \"skills\": \"./skills/\",\n  \"mcpServers\": \"./.mcp.json\",\n  \"interface\": {\n    \"displayName\": \"Cowart\",\n    \"shortDescription\": \"Your fullscreen project canvas\",\n    \"longDescription\": \"Cowart brings a native tldraw canvas into Codex for visual planning and creative iteration. Open Cowart from global navigation and pin it with the host pin control. The sidebar opens a single canvas in the system Documents/Cowart folder, creating the first page when needed. Project conversations with projectDir keep their own project canvas. Image, HTML, Slides, AI film and annotation workflows reuse the open canvas.\",\n    \"developerName\": \"ZHONG XIN\",\n    \"category\": \"Productivity\",\n    \"websiteURL\": \"https://www.jiqiren.ai\",\n    \"brandColor\": \"#25BFEF\",\n    \"logo\": \"./assets/app-icon.png\",\n    \"composerIcon\": \"./assets/app-icon.png\",\n    \"capabilities\": [\n      \"Fullscreen canvas\",\n      \"Sidebar entrypoint\",\n      \"AI image generation\",\n      \"Annotation-driven editing\",\n      \"Project-local persistence\",\n      \"AI motion films with playback\"\n    ],\n    \"defaultPrompt\": [\n      \"Open the Cowart canvas for this project.\",\n      \"Use my Cowart annotation screenshot to generate a clean revised image beside the original.\",\n      \"Generate a new image into the selected Cowart AI image holder.\",\n      \"Generate an AI motion film into the selected Cowart film holder using cowart-film-gen.\"\n    ]\n  }\n}\n\n<!-- File: plugin.json (Tokens: ~512 | Category: plugin-manifest) -->\n{\n  \"$schema\": \"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json\",\n  \"name\": \"cowart\",\n  \"version\": \"0.1.38\",\n  \"description\": \"A native fullscreen tldraw canvas for images, HTML, Slides and AI motion films. Open the canvas with Cowart MCP and reuse it for generation and playback.\",\n  \"author\": {\n    \"name\": \"ZHONG XIN\",\n    \"email\": \"zhongxin123456@gmail.com\",\n    \"url\": \"https://www.jiqiren.ai\"\n  },\n  \"homepage\": \"https://www.jiqiren.ai\",\n  \"repository\": \"https://github.com/zhongerxin/Cowart\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"canvas\",\n    \"tldraw\",\n    \"whiteboard\",\n    \"image-generation\",\n    \"visual-collaboration\"\n  ],\n  \"extensions\": {\n    \"com.openai\": {\n      \"interface\": {\n        \"displayName\": \"Cowart\",\n        \"shortDescription\": \"Your fullscreen project canvas\",\n        \"longDescription\": \"Cowart brings a native tldraw canvas into Codex for visual planning and creative iteration. Open Cowart from global navigation and pin it with the host pin control. The sidebar opens a single canvas in the system Documents/Cowart folder, creating the first page when needed. Project conversations with projectDir keep their own project canvas. Image, HTML, Slides, AI film and annotation workflows reuse the open canvas.\",\n        \"developerName\": \"ZHONG XIN\",\n        \"category\": \"Productivity\",\n        \"websiteURL\": \"https://www.jiqiren.ai\",\n        \"brandColor\": \"#25BFEF\",\n        \"logo\": \"./assets/app-icon.png\",\n        \"composerIcon\": \"./assets/app-icon.png\",\n        \"capabilities\": [\n          \"Fullscreen canvas\",\n          \"Sidebar entrypoint\",\n          \"AI image generation\",\n          \"Annotation-driven editing\",\n          \"Project-local persistence\",\n          \"AI motion films with playback\"\n        ],\n        \"defaultPrompt\": [\n          \"Open the Cowart canvas for this project.\",\n          \"Use my Cowart annotation screenshot to generate a clean revised image beside the original.\",\n          \"Generate a new image into the selected Cowart AI image holder.\",\n          \"Generate an AI motion film into the selected Cowart film holder using cowart-film-gen.\"\n        ]\n      }\n    }\n  }\n}\n\n<!-- File: mcp.json (Tokens: ~80 | Category: mcp-config) -->\n{\n  \"$schema\": \"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json\",\n  \"mcpServers\": {\n    \"cowart_mcp\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\n        \"./scripts/start-mcp.mjs\"\n      ],\n      \"cwd\": \"./\"\n    }\n  }\n}\n</yakaai_skills>"}