Sequence writer
@gtmengineer/sequence-writer
Write multi-step outbound sequences (email, LinkedIn, call) built on a real reason to reach out, with personalization slots instead of fake personalization. A built-in linter blocks spam phrases, fake Re: subjects, invented familiarity, unsourced stats, broken slots, too many links, and rushed cadence before anything is loaded into a sending tool.
- Activity
- New: be the first to try it
- Installs
- 0 installs
- Likes
- 0 likes
- Clones
- 0 clones
- 1{
- 2 "name": "sequence-writer",
- 3 "owner": "gtmengineer",
- 4 "version": "1.0.0",
- 5 "type": "skill",
- 6 "description": "Write multi-step outbound sequences (email, LinkedIn, call) built on a real reason to reach out, with personalization slots instead of fake personalization. A built-in linter blocks spam phrases, fake Re: subjects, invented familiarity, unsourced stats, broken slots, too many links, and rushed cadence before anything is loaded into a sending tool.",
- 7 "category": "content",
- 8 "license": "MIT",
- 9 "compat": [
- 10 "claude-code"
- 11 ],
- 12 "permissions": {
- 13 "shell": [
- 14 "node scripts/lint-sequence.mjs"
- 15 ],
- 16 "files": {
- 17 "read": [
- 18 "./data/**"
- 19 ],
- 20 "write": [
- 21 "./data/**",
- 22 "./out/**"
- 23 ]
- 24 }
- 25 },
- 26 "tests": {
- 27 "cases": [
- 28 {
- 29 "name": "a good sequence lints clean and previews with missing values flagged",
- 30 "inputs": {
- 31 "data/sequence.json": "{\n \"name\": \"RevOps leaders at companies that just opened a second sales team\",\n \"persona\": \"Head of Revenue Operations, 200 to 2,000 employees\",\n \"signal\": \"Hiring a second sales leader or a new regional sales team in the last 60 days\",\n \"slots\": [\n \"first_name\",\n \"company\",\n \"trigger\",\n \"observation\",\n \"peer_company\",\n \"sender_name\"\n ],\n \"steps\": [\n {\n \"day\": 1,\n \"channel\": \"email\",\n \"subject\": \"{{company}}'s new sales team\",\n \"body\": \"Hi {{first_name}},\\n\\nSaw {{trigger}}. When a second team spins up, the forecast usually splits into two spreadsheets within a quarter.\\n\\n{{observation}}\\n\\nWe help RevOps teams keep one forecast and one set of routing rules as teams multiply. {{peer_company}} used it to get their Monday forecast call back to 30 minutes.\\n\\nWorth comparing notes on how you plan to handle it?\\n\\n{{sender_name}}\",\n \"sources\": [\n \"Customer story approved by the customer, on file\"\n ]\n },\n {\n \"day\": 4,\n \"channel\": \"linkedin\",\n \"body\": \"Hi {{first_name}}, I work with RevOps leads at companies adding sales teams. Would be glad to connect.\"\n },\n {\n \"day\": 7,\n \"channel\": \"email\",\n \"in_thread\": true,\n \"body\": \"Hi {{first_name}},\\n\\nOne more thought: the first thing that usually breaks is lead routing, because new territories get bolted onto old rules. Is that on your list this quarter, or already handled?\\n\\n{{sender_name}}\"\n },\n {\n \"day\": 12,\n \"channel\": \"email\",\n \"subject\": \"routing rules for two teams\",\n \"body\": \"Hi {{first_name}},\\n\\nWhen {{peer_company}} split routing across two teams, a one-page checklist saved them a week of rework. Want me to send it over?\\n\\nIf this is not your area, tell me who owns it and I will stop here.\\n\\n{{sender_name}}\"\n }\n ]\n}\n",
- 32 "data/contact.json": "{\n \"first_name\": \"Sam\",\n \"company\": \"Northwind Traders\",\n \"trigger\": \"you are hiring a Head of Sales for EMEA\",\n \"observation\": \"Your careers page lists four new AE roles in the same region.\",\n \"peer_company\": \"a 600-person software company\",\n \"sender_name\": \"\"\n}\n"
- 33 },
- 34 "checks": [
- 35 {
- 36 "type": "command_exits_zero",
- 37 "command": "node scripts/lint-sequence.mjs data/sequence.json --strict --preview data/contact.json --out out"
- 38 },
- 39 {
- 40 "type": "file_contains",
- 41 "path": "out/lint-preview.md",
- 42 "text": "Missing values: sender_name."
- 43 },
- 44 {
- 45 "type": "file_not_contains",
- 46 "path": "out/lint-preview.md",
- 47 "text": "{{"
- 48 },
- 49 {
- 50 "type": "output_matches_schema",
- 51 "path": "out/lint.json",
- 52 "schema": {
- 53 "type": "object",
- 54 "required": [
- 55 "errors",
- 56 "warnings",
- 57 "step_issues"
- 58 ],
- 59 "properties": {
- 60 "errors": {
- 61 "const": 0
- 62 },
- 63 "warnings": {
- 64 "const": 0
- 65 },
- 66 "steps": {
- 67 "const": 4
- 68 }
- 69 }
- 70 }
- 71 }
- 72 ]
- 73 },
- 74 {
- 75 "name": "a spammy draft gets errors for each problem",
- 76 "inputs": {
- 77 "data/draft.json": "{\n \"name\": \"First draft (needs work)\",\n \"slots\": [\"first_name\", \"company\"],\n \"steps\": [\n {\n \"day\": 1,\n \"channel\": \"email\",\n \"subject\": \"Re: quick question\",\n \"body\": \"Hi [First Name],\\n\\nAs promised, here is how we GUARANTEE a 3x pipeline lift for {{company}}. We are the industry-leading platform!! Check https://example.com/demo and https://example.com/pricing.\\n\\nThanks\"\n },\n {\n \"day\": 2,\n \"channel\": \"email\",\n \"in_thread\": true,\n \"body\": \"Just bumping this to the top of your inbox, {{first_name}}. Act now, limited time pricing for {{segment}}.\"\n }\n ]\n}\n"
- 78 },
- 79 "checks": [
- 80 {
- 81 "type": "command_exits_zero",
- 82 "command": "node scripts/lint-sequence.mjs data/draft.json --out out"
- 83 },
- 84 {
- 85 "type": "file_contains",
- 86 "path": "out/lint.md",
- 87 "text": "subject starts with \"Re:\" but this is not a real reply"
- 88 },
- 89 {
- 90 "type": "file_contains",
- 91 "path": "out/lint.md",
- 92 "text": "{{segment}} is not in the sequence"
- 93 },
- 94 {
- 95 "type": "output_matches_schema",
- 96 "path": "out/lint.json",
- 97 "schema": {
- 98 "type": "object",
- 99 "properties": {
- 100 "errors": {
- 101 "const": 8
- 102 },
- 103 "warnings": {
- 104 "const": 10
- 105 }
- 106 }
- 107 }
- 108 }
- 109 ]
- 110 }
- 111 ]
- 112 }
- 113}
