← SurferCONTENT HISTORY

Update to Surfer

Snapshot Oct 7, 2026 · 18:03 UTC · version 0.1.0

Collection source: downloaded plugin package.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "description": "Use when the user has existing content, a URL or a draft, and wants to improve its Surfer SEO Score, AI Search Score, or both. Triggers include \"optimize my article\", \"improve this page's content score\", \"auto-optimize this\", \"make this rank better\", \"optimize for SEO and AI search\", and \"improve my AI or LLM visibility\". For writing a new article from scratch, use surfer-write-article instead.",
  "included_files": [
    {
      "relative_path": "LICENSE",
      "size_in_bytes": 1079
    },
    {
      "relative_path": "agents/openai.yaml",
      "size_in_bytes": 453
    }
  ],
  "name": "surfer-optimize-content",
  "skill_md_contents": "---\nname: surfer-optimize-content\ndescription: >-\n  Use when the user has existing content, a URL or a draft, and wants to improve its Surfer SEO\n  Score, AI Search Score, or both. Triggers include \"optimize my article\", \"improve this page's\n  content score\", \"auto-optimize this\", \"make this rank better\", \"optimize for SEO and AI search\",\n  and \"improve my AI or LLM visibility\". For writing a new article from scratch, use\n  surfer-write-article instead.\nlicense: MIT\n---\n\n# Surfer: Optimize Existing Content\n\n## Overview\n\nRaise the Surfer score dimensions the user selected for a page or draft, working through a Content\nEditor. Treat the unified Content Score as a diagnostic snapshot. Optimize against the explicit SEO\nor AI Search targets the user cares about.\n\n## Prerequisites\n\n- Require connected Surfer MCP tools. For setup or connection failures, use `surfer-connect`;\n  ask to install it if missing. If a required tool is unavailable, name it and stop.\n- Resolve an active `workspace_id` with `workspace__list`. If several workspaces are active, ask\n  the caller which `workspace_id` to use rather than guessing.\n- Require a target keyword and either an import URL or raw HTML or Markdown. Ask for a missing\n  keyword rather than guessing it from the page alone.\n- Ask which dimensions matter: SEO, AI Search, or both. If the user says only \"optimize\", default to\n  SEO 70+. If they ask for both and give no targets, default to 70+ for each and say so. A missing\n  AI Search score does not mean zero.\n- Treat brand knowledge, content type or template, custom instructions, and competitor selection as\n  Content Editor setup, collected before the create: the brand profile is applied through the\n  `use_brand_knowledge` toggle and cannot be inspected or edited from here, the content type is one\n  `custom_template_id` or `surfer_template` (mutually exclusive), instructions go in\n  `custom_instructions`, and competitors are read and changed through `seo_guidelines__get` and\n  `seo_guidelines__update_competitors`. When both template fields are omitted, Surfer picks a\n  template itself during analysis. It may pick the workspace default, an AI-chosen preset or custom\n  template, or none, so a request for no template cannot be guaranteed. Verify which template took\n  effect and swap it only when the user asks. A template, once set, can be swapped but not removed.\n  `content_editor__update` rejects an update that clears `custom_template_id` without supplying a\n  `surfer_template`. Omitting `custom_voice_id` applies the workspace default voice. To honor a\n  request for no voice, send `custom_voice_id: null`.\n\nUse bounded waits only. On an explicit failure, an unavailable score, or a timeout, report the id\nand state. Never poll indefinitely.\n\n## Playbook\n\n1. **Create or reuse a Content Editor.** Reuse a matching editor through `content_editor__list` when\n   the user supplies one or asks to continue it. Omit `workspace_id` on that list call for an\n   org-wide search. Otherwise call `content_editor__create` once with `main_keyword`, location,\n   device, the full initial setup, and `import_content_url` for a live page. Default the location to\n   United States and the device to mobile. For pasted text, omit the import URL and load the body\n   after initialization. A create consumes a credit, so pass an `idempotency_key`. Retry a timeout\n   or an ambiguous failure with the same key. Surfer then returns the original editor instead of\n   creating a duplicate.\n\n2. **Wait and verify the setup.** Await the completion signal or poll `content_editor__get` until\n   `state` is `completed`. Read `content_editor__get`. If the user asked to review competitors,\n   read the `competitors` block of `seo_guidelines__get`. Report the effective brand toggle,\n   template or voice, instructions, and competitors. Apply changes only after user approval, with\n   `content_editor__update` or `seo_guidelines__update_competitors`, then re-read the affected\n   guidelines.\n\n3. **Load content and establish the baseline.** For a pasted draft, call `content__update`, then\n   re-fetch with `content__get`. Read `content_score__get` for the unified `total` plus the `seo`\n   and `ai_search` subscores. A `loading` or `calculating` status means the score is still\n   settling, so keep waiting until each selected subscore's `status` is `ready`. An `ai_search`\n   status of `error` or `unavailable` is terminal. Report it and stop waiting. Before the next\n   mutation, record the `calculated_at` of the `seo` and `ai_search` subscores. The `total` has no\n   `calculated_at`.\n\n4. **Read only the guidance needed.** For SEO, read `seo_guidelines__get`, one brief that carries the\n   structure targets, terms, topics, questions, and competitors. For AI Search, read the facts with\n   `ai_search_guidelines__list_facts`. Check the analysis readiness reported by the MCP tool: wait\n   with a bound while analysis runs, and report failure or a timeout instead of treating incomplete\n   facts as final. The separate `ai_search` score reaching `ready` does not establish facts analysis\n   completion. `ai_search_guidelines__get` returns the facts plus the score, its status, and the fact\n   count. Retain every fact's source URL and `cited_by` context.\n\n5. **Choose an optimization path**, and ask when the user has no preference.\n   - Call `auto_optimize__run` once per requested pass; it edits the document directly. Poll\n     `auto_optimize__get` by the returned job id, or resume polling when continuing a known run.\n     Each accepted start spends a credit and can cancel an earlier run, so do not automatically\n     repeat a start whose response was lost. If no job id is available, report the outcome as unknown\n     and stop. A `completed` job has a result of `optimized` or `nothing_to_optimize`. Stop on a\n     `failed` state or a quota error.\n   - A guided edit revises the draft against the selected guidelines, without keyword stuffing or\n     unsupported claims, then calls `content__update`. Preserve source attribution for AI Search\n     facts, and re-fetch the canonical stored body with `content__get` because Surfer sanitizes it.\n\n6. **Recalculate and compare.** After either path, re-read the stored content and all selected scores\n   with `content_score__get`. After a direct content update, trust a subscore only once its `status`\n   is `ready` and its `calculated_at` has advanced past the pre-mutation value. A `loading` or\n   `calculating` status may still carry the stale score. The `total` has no `calculated_at`, so\n   gate it on `status` alone. If AI Search reports `error` or `unavailable`, report why and do not\n   claim the combined target was reached.\n\n7. **Iterate with a stopping rule.** Address the largest remaining SEO or AI Search gap, then repeat\n   steps 4 to 6. Stop when every selected target is met, when auto-optimize reports\n   `nothing_to_optimize`, when the last useful gain is under about one point, or after 3 to 4 rounds.\n   Report the baseline and final values for the SEO, AI Search, and unified Content Score separately.\n"
}

SHA-256 of public snapshot: 2b55e41f8b22f6c5ac4123b8adafc2f6c06fe65764c6f7e8c87877aafa633729