From para-obsidian
Analyze web clippings, create resource notes with Layer 1 content, and return lightweight proposals. Handles enrichment, analysis, note creation, and Layer 1 injection so content never flows through coordinator. Worker skill for triage orchestrator.
How this skill is triggered — by the user, by Claude, or both
Slash command
/para-obsidian:analyze-webThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Analyze a single web clipping, **create the resource note with Layer 1 content**, and return a lightweight proposal.
Analyze a single web clipping, create the resource note with Layer 1 content, and return a lightweight proposal.
Key design: This skill creates the resource note AND populates Layer 1 before returning. The full content stays in subagent context - only the proposal flows back to the coordinator.
You receive:
file: Path to clipping in inbox (e.g., 00 Inbox/✂️ Article Title.md)areas: Available areas in vaultprojects: Available projects in vaultReturn a JSON proposal per @plugins/para-obsidian/skills/triage/references/proposal-schema.md.
Key: Use area (single wikilink), project (single wikilink or null), resourceType (camelCase). Include file, type: "clipping", created, and layer1_injected alongside the standard proposal fields.
para_read({ file: "[input file]", response_format: "json" })
Extract frontmatter fields (source, domain, capture_reason, pre-filled areas/projects) from the YAML header in the para_read response. Do NOT call para_fm_get separately — para_read returns the full file including frontmatter.
Also extract existing body content.
CRITICAL: Select tool based on domain. Use ToolSearch to load deferred tools before calling them.
| Domain | Tool | ToolSearch Query |
|---|---|---|
youtube.com / youtu.be | get_transcript (fallback: get_video_info) | "youtube transcript" |
x.com / twitter.com | x_get_tweet (parse tweet_id from URL) | "x-api tweet" |
github.com / other articles | firecrawl_scrape | "firecrawl scrape" |
X/Twitter is MANDATORY enrichment — Web Clipper captures only stubs. Always fetch via X-API regardless of clipping content.
See @plugins/para-obsidian/skills/triage/references/enrichment-strategies.md for the full routing table and constraints.
See @plugins/para-obsidian/references/content-sourcing/url-routing.md for detailed per-domain patterns.
Determine:
resource) or reference (gift, booking, etc.)?article, tutorial, reference, thread, issue, ideavideo, article, thread, documentBefore calling para_create, verify your args object includes these critical fields:
summary — one-sentence description of the resourceareas — wikilink(s) to vault areassource_format — article, thread, video, documentresource_type — article, tutorial, reference, thread, issue, ideaIf any field is missing but you determined a value in Step 3, add it to args now.
This is where content stays isolated. Use para_create with the content parameter to create the note AND inject Layer 1 in a single tool call:
para_create({
template: "resource",
title: proposed_title,
args: { ...fields from validArgs },
content: {
"<content-target-heading>": formattedLayerOneContent
},
response_format: "json"
})
The content parameter maps heading names to body content. The CLI internally creates the note, injects content into the matching section, and auto-commits — all in one invocation. No separate para_commit or para_replace_section calls needed.
Content target heading: Use creation_meta.contentTargets[0] from template fields (typically "Layer 1: Captured Notes"). If template fields were pre-loaded in the prompt context (triage mode), use those directly.
See @references/layer1-formatting.md for Layer 1 content formatting patterns (articles, YouTube, threads).
If para_create fails: Set created: null, layer1_injected: null, and continue with the proposal. The content parameter failure is atomic — no partial state.
During triage: Skip this step entirely. Set verification_status: "pending_coordinator" and verification_issues: []. The coordinator handles verification in Phase 2.5 — it stamps and checks all critical fields from PROPOSAL_JSON.
Standalone callers (non-triage): Call para_fm_get on the created file. Compare each critical field:
| Field | Your intended value | File value | Action |
|---|---|---|---|
summary | from Step 3 | from para_fm_get | MISMATCH → repair |
areas | from Step 3 | from para_fm_get | MISMATCH → repair |
source_format | from Step 3 | from para_fm_get | MISMATCH → repair |
resource_type | from Step 3 | from para_fm_get | MISMATCH → repair |
If any MISMATCH: para_fm_set({ file, set: { ...repairs }, response_format: "json" })
Set verification_status: "verified" (all match), "repaired" (fixed), "needs_review" (empty fields), "skipped" (para_create failed).
Return the lightweight JSON proposal. The resource is already created with Layer 1 populated.
{
"file": "00 Inbox/✂️ Original.md",
"type": "clipping",
"proposed_title": "Title",
"proposed_template": "resource",
"summary": "...",
"created": "03 Resources/Title.md",
"layer1_injected": true,
"verification_status": "verified",
"verification_issues": [],
...
}
The coordinator receives only this ~500 byte proposal, not the 10-20k token content.
| Content Type | Template | Resource Type |
|---|---|---|
| Tutorial/how-to | resource | tutorial |
| News/opinion | resource | article |
| Twitter thread | resource | thread |
| API docs | resource | reference |
| GitHub issue | resource | issue |
| Product page | gift | - |
| Booking confirmation | booking | - |
| Flight/hotel | booking | - |
| Level | Meaning |
|---|---|
high | Clear content, obvious categorization |
medium | Reasonable guess, user may want to adjust |
low | Ambiguous content, multiple valid interpretations |
{
"file": "00 Inbox/✂️ Matt Pocock TypeScript Tips.md",
"type": "clipping",
"proposed_title": "TypeScript 5.5 Inference Improvements",
"proposed_template": "resource",
"summary": "Matt Pocock explains new type inference features in TypeScript 5.5, focusing on const type parameters and improved narrowing in control flow.",
"categorization_hints": [
"Const type parameters preserve literal types without 'as const'",
"Control flow analysis now narrows in more cases",
"New 'satisfies' patterns for type-safe object literals"
],
"area": "[[🌱 AI Practice]]",
"project": "[[🎯 TypeScript Migration]]",
"resourceType": "tutorial",
"source_format": "thread",
"author": "Matt Pocock",
"confidence": "high",
"notes": null,
"created": "03 Resources/TypeScript 5.5 Inference Improvements.md",
"layer1_injected": true,
"verification_status": "verified",
"verification_issues": []
}
| Scenario | Action |
|---|---|
para_create (with content) fails | Set created: null, layer1_injected: null, return error proposal |
| Content empty/unparseable | Create note without content parameter, set layer1_injected: false |
Atomic creation: When using the content parameter, creation and injection are a single atomic operation. If it fails, there's no partial state to clean up.
npx claudepluginhub nathanvale/side-quest-marketplace-old --plugin para-obsidianIngests articles, URLs, videos, and book notes into Obsidian Resources notes after discussing key ideas with the user. Automates note creation with synthesis and linking.
Creates, edits, and verifies skills using a test-driven development approach with pressure scenarios and subagents.