Platform Support: This skill works across all platforms (Claude, Cursor, Factory, OpenCode) with platform-specific invocation methods but consistent metadata structure.
Creation: Use create_artifact to finalize a code block or document into a persistent artifact.
- Include metadata:
workflow_id, step_number, dependencies from registry
- Add validation status from gate file if available
Distribution: Use share_artifact to push the artifact to the Claude Project feed or external integrations.
- Publish to targets specified in registry metadata or default to
["project_feed"]
Publishing: Use publish_artifact to formally publish an artifact, updating its published status and published_at timestamp in the artifact registry.
- This is the formal publishing step that marks an artifact as published
- Updates registry metadata with publishing status
Update Registry: After publishing (success or failure):
- Use
updateArtifactPublishingStatus(runId, artifactName, status) from .claude/tools/run-manager.mjs
- Update
published: true/false in registry metadata
- Set
published_at timestamp on success
- Update
publish_status: 'success' or 'failed'
- Record
publish_error if publication failed
- Add to
publish_attempts array for retry tracking
- Example call:
await updateArtifactPublishingStatus(runId, artifactName, {
published: true,
published_at: new Date().toISOString(),
publish_status: 'success',
attempt: {
timestamp: new Date().toISOString(),
status: 'success',
target: 'project_feed'
}
});
Error Handling & Retry:
- Retry Logic: If publication fails, retry up to
max_attempts (default: 3) with exponential backoff
- Backoff Strategy: Use delays from
retry_config: initial_delay_ms (1000ms), then 2x, 4x, up to max_delay_ms (8000ms)
- Status Tracking: Track each attempt in
publish_attempts array with timestamp and error using updateArtifactPublishingStatus()
- Validation Check: Only publish artifacts with
validation_status: 'pass' unless validation_required: false override
- Notifications: Log publishing success/failure; include in gate file if available
- Fallback: If all retries fail, mark as
publish_status: 'failed' and log error for manual intervention
- Retry Implementation:
async function publishWithRetry(artifact, runId, maxRetries = 3) {
const delays = [1000, 2000, 4000]; // From retry_config
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
await publishArtifact(artifact);
await updateArtifactPublishingStatus(runId, artifact.name, {
status: 'success',
published: true,
published_at: new Date().toISOString(),
attempt: { timestamp: new Date().toISOString(), status: 'success' }
});
return;
} catch (error) {
await updateArtifactPublishingStatus(runId, artifact.name, {
status: attempt === maxRetries - 1 ? 'failed' : 'pending',
publish_error: error.message,
attempt: { timestamp: new Date().toISOString(), status: 'failed', error: error.message }
});
if (attempt < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, delays[attempt]));
}
}
}
throw new Error(`Publishing failed after ${maxRetries} attempts`);
}
Transient Errors (network, rate limits):
- Retry with exponential backoff: 1s, 2s, 4s
- Maximum 3 retries
- Log each attempt in registry metadata
Permanent Errors (invalid artifact, permission denied):
- Fail immediately (no retry)
- Log error in registry:
publish_error
- Set
publish_status: 'failed'
- Include error details in gate file if available
Status Tracking:
metadata: {
publish_attempts: [
{ timestamp: "2025-11-29T10:00:00Z", status: "failed", error: "Network timeout" },
{ timestamp: "2025-11-29T10:00:01Z", status: "success" }
],
publish_status: "success" | "failed" | "pending",
publish_error: null | "Error message"
}
Notifications:
- Log success: "✅ Artifact published successfully to project_feed"
- Log failure: "❌ Artifact publishing failed after 3 retries: [error]"
- Include in gate file validation results if available
- Post-Tool Trigger: This skill is often invoked automatically after a
PostToolUse hook to snapshot the results of a tool execution.
- Factory Droid: Published artifacts are the primary way Factory Droids consume instructions from Claude.
- Publishing Policy: The
publish_policy in the frontmatter dictates when artifacts are automatically published:
manual: Requires explicit publish_artifact call.
auto-on-pass: Automatically publishes if the artifact's validation status is 'pass'.
auto-on-complete: Automatically publishes upon workflow completion.
- Artifact Registry Integration:
- Use
readArtifactRegistry(runId) from .claude/tools/run-manager.mjs to check registry
- Check artifact registry for
publishable: true metadata to auto-publish
- Use
updateArtifactPublishingStatus(runId, artifactName, status) to update registry after publication
- Read
workflow_id and step_number from registry metadata
- Track publishing attempts and errors in registry via
publish_attempts array
- Migration Note: Prefer run-manager.mjs over artifact-registry.mjs (deprecated)
Publishing Policy Examples:
Manual Publishing (publish_policy: manual):
# In workflow YAML or skill frontmatter
publish_policy: manual
- Artifacts are only published when explicitly requested
- Use: "Publish this artifact" or
publish_artifact tool call
- Example: User reviews artifact, then explicitly publishes it
Auto-on-Pass (publish_policy: auto-on-pass):
# In workflow YAML or skill frontmatter
publish_policy: auto-on-pass
- Artifacts are automatically published when validation status is 'pass'
- Use: When you want to publish all validated artifacts automatically
- Example: After gate file validation passes, artifact is automatically published
- Implementation:
// After gate validation passes
if (artifact.validationStatus === 'pass' && publishPolicy === 'auto-on-pass') {
await publishArtifact(artifact);
await updateArtifactPublishingStatus(runId, artifact.name, {
published: true,
published_at: new Date().toISOString(),
publish_status: 'success',
});
}
Auto-on-Complete (publish_policy: auto-on-complete):
# In workflow YAML or skill frontmatter
publish_policy: auto-on-complete
- Artifacts are automatically published when workflow completes
- Use: When you want to publish all artifacts at workflow end
- Example: At workflow completion, all artifacts with
publishable: true are published
- Implementation:
// At workflow completion
if (workflowStatus === 'completed' && publishPolicy === 'auto-on-complete') {
const registry = await readArtifactRegistry(runId);
for (const [name, artifact] of Object.entries(registry.artifacts)) {
if (artifact.publishable && !artifact.published) {
await publishArtifact(artifact);
await updateArtifactPublishingStatus(runId, name, {
published: true,
published_at: new Date().toISOString(),
publish_status: 'success',
});
}
}
}
Configuring Publish Targets Per Artifact:
// When registering artifact
await registerArtifact(runId, {
name: 'plan-123.json',
step: 0,
agent: 'planner',
publishable: true,
publish_targets: ['project_feed', 'cursor'], // Multiple targets
// ... other fields
});
Handling Publishing Failures in Workflows:
- If publishing fails, workflow continues (non-blocking)
- Publishing errors are logged in registry:
publish_error
- Failed artifacts can be retried manually or in next workflow run
- Gate files include publishing status for visibility
- Use
create_artifact and share_artifact tools directly
- Invoke: "Use artifact-publisher skill to publish this artifact"
Cursor:
- Use
@artifact-publisher mention
- Invoke: "Use @artifact-publisher to publish this plan"
Factory:
- Use Task tool with skill
- Invoke: "Run Task tool with skill artifact-publisher to publish this spec"
OpenCode:
- Use file system operations
- Invoke: "Publish artifact to .opencode/context/artifacts/published/"
Cross-Platform Metadata:
All platforms should use consistent metadata structure:
{
"id": "artifact-{timestamp}-{sequence}",
"type": "plan|architecture|specification|implementation|test-results",
"title": "Artifact Title",
"created": "ISO 8601 timestamp",
"workflow_id": "workflow-id",
"step_number": 0,
"agent": "agent-name",
"dependencies": ["artifact1.json", "artifact2.json"],
"validation_status": "pass|fail|pending",
"tags": ["tag1", "tag2"],
"publish_targets": ["project_feed", "cursor"],
"published": true,
"published_at": "ISO 8601 timestamp"
}
create_artifact --title "System Architecture" --type "markdown" --content "..."
share_artifact --id <artifact_id> --target "project_feed"
Use @artifact-publisher to publish this plan
Run Task tool with skill artifact-publisher to publish this spec
1---2name: artifact-publisher3description: Publish and share Claude Artifacts with Projects, Cursor, and downstream agents. Use when a user wants to "save", "share", or "finalize" a generated artifact.4---5
6<identity>
7Artifact Publisher - Handles the lifecycle of Claude Artifacts, ensuring they are properly versioned and distributed.
8
9**Platform Support**: This skill works across all platforms (Claude, Cursor, Factory, OpenCode) with platform-specific invocation methods but consistent metadata structure.
10</identity>
11
12<capabilities>
13- Publishing and sharing Claude Artifacts with Projects, Cursor, and downstream agents
14- Saving, sharing, or finalizing generated artifacts
15- Versioning artifacts
16- Distributing artifacts to external integrations
17</capabilities>
18
19<instructions>
20<execution_process>
211. **Check Registry**: If artifact is registered, check registry metadata for:
22 - Use `readArtifactRegistry(runId)` from `.claude/tools/run-manager.mjs` to load registry
23 - Check `publishable: true` - Should this artifact be published?
24 - Check `publish_targets` - Where to publish (e.g., `["project_feed", "cursor"]`)
25 - Extract `workflow_id` and `step_number` from registry metadata
26
272. **Creation**: Use `create_artifact` to finalize a code block or document into a persistent artifact.
28 - Include metadata: `workflow_id`, `step_number`, `dependencies` from registry
29 - Add validation status from gate file if available
30
313. **Distribution**: Use `share_artifact` to push the artifact to the Claude Project feed or external integrations.
32 - Publish to targets specified in registry metadata or default to `["project_feed"]`
33
344. **Publishing**: Use `publish_artifact` to formally publish an artifact, updating its `published` status and `published_at` timestamp in the artifact registry.
35 - This is the formal publishing step that marks an artifact as published
36 - Updates registry metadata with publishing status
37
385. **Update Registry**: After publishing (success or failure):
39 - Use `updateArtifactPublishingStatus(runId, artifactName, status)` from `.claude/tools/run-manager.mjs`
40 - Update `published: true/false` in registry metadata
41 - Set `published_at` timestamp on success
42 - Update `publish_status`: 'success' or 'failed'
43 - Record `publish_error` if publication failed
44 - Add to `publish_attempts` array for retry tracking
45 - Example call:
46 ```javascript
47 await updateArtifactPublishingStatus(runId, artifactName, {
48 published: true,
49 published_at: new Date().toISOString(),
50 publish_status: 'success',
51 attempt: {
52 timestamp: new Date().toISOString(),
53 status: 'success',
54 target: 'project_feed'
55 }
56 });
57 ```
58
596. **Error Handling & Retry**:
60 - **Retry Logic**: If publication fails, retry up to `max_attempts` (default: 3) with exponential backoff
61 - **Backoff Strategy**: Use delays from `retry_config`: initial_delay_ms (1000ms), then 2x, 4x, up to max_delay_ms (8000ms)
62 - **Status Tracking**: Track each attempt in `publish_attempts` array with timestamp and error using `updateArtifactPublishingStatus()`
63 - **Validation Check**: Only publish artifacts with `validation_status: 'pass'` unless `validation_required: false` override
64 - **Notifications**: Log publishing success/failure; include in gate file if available
65 - **Fallback**: If all retries fail, mark as `publish_status: 'failed'` and log error for manual intervention
66 - **Retry Implementation**:
67 ```javascript
68 async function publishWithRetry(artifact, runId, maxRetries = 3) {
69 const delays = [1000, 2000, 4000]; // From retry_config
70 for (let attempt = 0; attempt < maxRetries; attempt++) {
71 try {
72 await publishArtifact(artifact);
73 await updateArtifactPublishingStatus(runId, artifact.name, {
74 status: 'success',
75 published: true,
76 published_at: new Date().toISOString(),
77 attempt: { timestamp: new Date().toISOString(), status: 'success' }
78 });
79 return;
80 } catch (error) {
81 await updateArtifactPublishingStatus(runId, artifact.name, {
82 status: attempt === maxRetries - 1 ? 'failed' : 'pending',
83 publish_error: error.message,
84 attempt: { timestamp: new Date().toISOString(), status: 'failed', error: error.message }
85 });
86 if (attempt < maxRetries - 1) {
87 await new Promise(resolve => setTimeout(resolve, delays[attempt]));
88 }
89 }
90 }
91 throw new Error(`Publishing failed after ${maxRetries} attempts`);
92 }
93 ```
94</execution_process>
95
96<error_handling>
97**Publishing Failures**:
98
991. **Transient Errors** (network, rate limits):
100 - Retry with exponential backoff: 1s, 2s, 4s
101 - Maximum 3 retries
102 - Log each attempt in registry metadata
103
1042. **Permanent Errors** (invalid artifact, permission denied):
105 - Fail immediately (no retry)
106 - Log error in registry: `publish_error`
107 - Set `publish_status: 'failed'`
108 - Include error details in gate file if available
109
1103. **Status Tracking**:
111
112 ```javascript
113 metadata: {
114 publish_attempts: [
115 { timestamp: "2025-11-29T10:00:00Z", status: "failed", error: "Network timeout" },
116 { timestamp: "2025-11-29T10:00:01Z", status: "success" }
117 ],
118 publish_status: "success" | "failed" | "pending",
119 publish_error: null | "Error message"
120 }
121 ```
122
1234. **Notifications**:
124 - Log success: "✅ Artifact published successfully to project_feed"
125 - Log failure: "❌ Artifact publishing failed after 3 retries: [error]"
126 - Include in gate file validation results if available
127 </error_handling>
128
129<workflow_integration>
130
131- **Post-Tool Trigger**: This skill is often invoked automatically after a `PostToolUse` hook to snapshot the results of a tool execution.
132- **Factory Droid**: Published artifacts are the primary way Factory Droids consume instructions from Claude.
133- **Publishing Policy**: The `publish_policy` in the frontmatter dictates when artifacts are automatically published:
134 - `manual`: Requires explicit `publish_artifact` call.
135 - `auto-on-pass`: Automatically publishes if the artifact's validation status is 'pass'.
136 - `auto-on-complete`: Automatically publishes upon workflow completion.
137- **Artifact Registry Integration**:
138 - Use `readArtifactRegistry(runId)` from `.claude/tools/run-manager.mjs` to check registry
139 - Check artifact registry for `publishable: true` metadata to auto-publish
140 - Use `updateArtifactPublishingStatus(runId, artifactName, status)` to update registry after publication
141 - Read `workflow_id` and `step_number` from registry metadata
142 - Track publishing attempts and errors in registry via `publish_attempts` array
143 - **Migration Note**: Prefer run-manager.mjs over artifact-registry.mjs (deprecated)
144
145**Publishing Policy Examples**:
146
1471. **Manual Publishing** (`publish_policy: manual`):
148
149 ```yaml
150 # In workflow YAML or skill frontmatter
151 publish_policy: manual
152 ```
153
154 - Artifacts are only published when explicitly requested
155 - Use: "Publish this artifact" or `publish_artifact` tool call
156 - Example: User reviews artifact, then explicitly publishes it
157
1582. **Auto-on-Pass** (`publish_policy: auto-on-pass`):
159
160 ```yaml
161 # In workflow YAML or skill frontmatter
162 publish_policy: auto-on-pass
163 ```
164
165 - Artifacts are automatically published when validation status is 'pass'
166 - Use: When you want to publish all validated artifacts automatically
167 - Example: After gate file validation passes, artifact is automatically published
168 - Implementation:
169
170 ```javascript
171 // After gate validation passes
172 if (artifact.validationStatus === 'pass' && publishPolicy === 'auto-on-pass') {
173 await publishArtifact(artifact);
174 await updateArtifactPublishingStatus(runId, artifact.name, {
175 published: true,
176 published_at: new Date().toISOString(),
177 publish_status: 'success',
178 });
179 }
180 ```
181
1823. **Auto-on-Complete** (`publish_policy: auto-on-complete`):
183
184 ```yaml
185 # In workflow YAML or skill frontmatter
186 publish_policy: auto-on-complete
187 ```
188
189 - Artifacts are automatically published when workflow completes
190 - Use: When you want to publish all artifacts at workflow end
191 - Example: At workflow completion, all artifacts with `publishable: true` are published
192 - Implementation:
193
194 ```javascript
195 // At workflow completion
196 if (workflowStatus === 'completed' && publishPolicy === 'auto-on-complete') {
197 const registry = await readArtifactRegistry(runId);
198 for (const [name, artifact] of Object.entries(registry.artifacts)) {
199 if (artifact.publishable && !artifact.published) {
200 await publishArtifact(artifact);
201 await updateArtifactPublishingStatus(runId, name, {
202 published: true,
203 published_at: new Date().toISOString(),
204 publish_status: 'success',
205 });
206 }
207 }
208 }
209 ```
210
211**Configuring Publish Targets Per Artifact**:
212
213```javascript
214// When registering artifact
215await registerArtifact(runId, {
216 name: 'plan-123.json',
217 step: 0,
218 agent: 'planner',
219 publishable: true,
220 publish_targets: ['project_feed', 'cursor'], // Multiple targets
221 // ... other fields
222});
223```
224
225**Handling Publishing Failures in Workflows**:
226
227- If publishing fails, workflow continues (non-blocking)
228- Publishing errors are logged in registry: `publish_error`
229- Failed artifacts can be retried manually or in next workflow run
230- Gate files include publishing status for visibility
231 </workflow_integration>
232 </instructions>
233
234<platform_invocation>
235**Claude (this platform)**:
236
237- Use `create_artifact` and `share_artifact` tools directly
238- Invoke: "Use artifact-publisher skill to publish this artifact"
239
240**Cursor**:
241
242- Use `@artifact-publisher` mention
243- Invoke: "Use @artifact-publisher to publish this plan"
244
245**Factory**:
246
247- Use Task tool with skill
248- Invoke: "Run Task tool with skill artifact-publisher to publish this spec"
249
250**OpenCode**:
251
252- Use file system operations
253- Invoke: "Publish artifact to .opencode/context/artifacts/published/"
254
255**Cross-Platform Metadata**:
256All platforms should use consistent metadata structure:
257
258```json
259{
260 "id": "artifact-{timestamp}-{sequence}",
261 "type": "plan|architecture|specification|implementation|test-results",
262 "title": "Artifact Title",
263 "created": "ISO 8601 timestamp",
264 "workflow_id": "workflow-id",
265 "step_number": 0,
266 "agent": "agent-name",
267 "dependencies": ["artifact1.json", "artifact2.json"],
268 "validation_status": "pass|fail|pending",
269 "tags": ["tag1", "tag2"],
270 "publish_targets": ["project_feed", "cursor"],
271 "published": true,
272 "published_at": "ISO 8601 timestamp"
273}
274```
275
276</platform_invocation>
277
278<examples>
279<usage_example>
280**Publishing a Design Doc (Claude)**:
281
282```
283create_artifact --title "System Architecture" --type "markdown" --content "..."
284share_artifact --id <artifact_id> --target "project_feed"
285```
286
287</usage_example>
288
289<usage_example>
290**Publishing a Plan (Cursor)**:
291
292```
293Use @artifact-publisher to publish this plan
294```
295
296</usage_example>
297
298<usage_example>
299**Publishing a Spec (Factory)**:
300
301```
302Run Task tool with skill artifact-publisher to publish this spec
303```
304
305</usage_example>
306</examples>