opencode-skills-collection 3.1.14 → 3.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-skills/.antigravity-install-manifest.json +36 -1
- package/bundled-skills/007/scripts/full_audit.py +34 -22
- package/bundled-skills/007/scripts/quick_scan.py +24 -15
- package/bundled-skills/007/scripts/scanners/dependency_scanner.py +31 -19
- package/bundled-skills/007/scripts/scanners/injection_scanner.py +24 -14
- package/bundled-skills/007/scripts/scanners/secrets_scanner.py +24 -14
- package/bundled-skills/007/scripts/score_calculator.py +25 -13
- package/bundled-skills/2slides-ppt-generator/scripts/download_slides_pages_voices.py +15 -1
- package/bundled-skills/aegisops-ai/SKILL.md +1 -1
- package/bundled-skills/agent-self-scheduling/SKILL.md +88 -0
- package/bundled-skills/alpha-vantage/SKILL.md +3 -1
- package/bundled-skills/anti-sleep/SKILL.md +90 -0
- package/bundled-skills/api-security-best-practices/SKILL.md +1 -1
- package/bundled-skills/app-store-optimization/SKILL.md +7 -0
- package/bundled-skills/audio-transcriber/scripts/transcribe.py +17 -4
- package/bundled-skills/azure-mgmt-botservice-py/SKILL.md +2 -1
- package/bundled-skills/azure-resource-manager-mysql-dotnet/SKILL.md +2 -1
- package/bundled-skills/azure-resource-manager-postgresql-dotnet/SKILL.md +2 -1
- package/bundled-skills/azure-resource-manager-sql-dotnet/SKILL.md +2 -1
- package/bundled-skills/biopython/SKILL.md +2 -1
- package/bundled-skills/brain-to-docs/SKILL.md +54 -0
- package/bundled-skills/browser-harness/SKILL.md +220 -0
- package/bundled-skills/browser-harness/references/install.md +132 -0
- package/bundled-skills/bumblebee/scripts/render_report.py +16 -3
- package/bundled-skills/bun-development/SKILL.md +1 -1
- package/bundled-skills/cc-skill-security-review/SKILL.md +2 -2
- package/bundled-skills/claude-monitor/scripts/monitor.py +15 -2
- package/bundled-skills/cmux/SKILL.md +250 -0
- package/bundled-skills/code-polish/SKILL.md +192 -0
- package/bundled-skills/code-review-checklist/SKILL.md +1 -1
- package/bundled-skills/codex-subagent/SKILL.md +117 -0
- package/bundled-skills/competitor-analysis/scripts/capture_screenshots.mjs +24 -3
- package/bundled-skills/competitor-analysis/scripts/compile_report.mjs +13 -2
- package/bundled-skills/competitor-analysis/scripts/extract_vs_names.mjs +23 -2
- package/bundled-skills/competitor-analysis/scripts/gate_candidates.mjs +21 -0
- package/bundled-skills/competitor-analysis/scripts/list_urls.mjs +23 -2
- package/bundled-skills/competitor-analysis/scripts/merge_partials.mjs +24 -3
- package/bundled-skills/container-security-hardening/SKILL.md +1 -1
- package/bundled-skills/content-creator/scripts/brand_voice_analyzer.py +15 -1
- package/bundled-skills/content-creator/scripts/seo_optimizer.py +15 -1
- package/bundled-skills/context-kit/SKILL.md +135 -0
- package/bundled-skills/cyber-audit/SKILL.md +138 -0
- package/bundled-skills/deepapi/SKILL.md +649 -0
- package/bundled-skills/delegating-to-agents/SKILL.md +64 -0
- package/bundled-skills/developer-signup-flow/SKILL.md +1 -1
- package/bundled-skills/diary/scripts/fetch_diaries.py +14 -1
- package/bundled-skills/diary/scripts/prepare_context.py +15 -2
- package/bundled-skills/diary/scripts/sync_to_notion.py +14 -1
- package/bundled-skills/dispatch/SKILL.md +19 -7
- package/bundled-skills/distribute-skill-to-all-agents/SKILL.md +85 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/docx-official/ooxml/scripts/pack.py +30 -3
- package/bundled-skills/docx-official/ooxml/scripts/unpack.py +16 -3
- package/bundled-skills/drizzle-migration-conflict/scripts/check_drizzle_migrations.py +27 -17
- package/bundled-skills/ecl-harness-engineer/agents/creator-config.md +17 -3
- package/bundled-skills/ecl-harness-engineer/references/environment-detection-guide.md +9 -5
- package/bundled-skills/effective-agent-skills/SKILL.md +333 -0
- package/bundled-skills/electron-development/SKILL.md +6 -2
- package/bundled-skills/environment-setup-guide/SKILL.md +2 -5
- package/bundled-skills/expo-ui/scripts/list-components.js +5 -1
- package/bundled-skills/fable-safe-prompt/SKILL.md +79 -0
- package/bundled-skills/folder-specific-claude-and-agents-md/SKILL.md +96 -0
- package/bundled-skills/frontend-slides/scripts/extract-pptx.py +18 -4
- package/bundled-skills/gcp-cloud-run/SKILL.md +2 -1
- package/bundled-skills/gemini-api-integration/SKILL.md +3 -1
- package/bundled-skills/gemini-live-api-dev/SKILL.md +2 -1
- package/bundled-skills/gemini-omni-flash-api/scripts/video/generate_video.py +49 -14
- package/bundled-skills/goal-loop/SKILL.md +175 -0
- package/bundled-skills/hugging-face-evaluation/SKILL.md +1 -1
- package/bundled-skills/hugging-face-jobs/SKILL.md +1 -1
- package/bundled-skills/hugging-face-jobs/scripts/finepdfs-stats.py +14 -1
- package/bundled-skills/hugging-face-model-trainer/scripts/convert_to_gguf.py +10 -1
- package/bundled-skills/hugo-to-markdown/scripts/inventory_hugo_rules.py +14 -1
- package/bundled-skills/image-generator/SKILL.md +3 -1
- package/bundled-skills/instagram/scripts/export.py +18 -7
- package/bundled-skills/interview-style-doc-building/SKILL.md +86 -0
- package/bundled-skills/junta-leiloeiros/scripts/export.py +19 -10
- package/bundled-skills/landing-page-generator/scripts/landing_page_scaffolder.py +15 -1
- package/bundled-skills/linear-claude-skill/SKILL.md +4 -2
- package/bundled-skills/linkedin-post-writer/SKILL.md +159 -0
- package/bundled-skills/linkedin-post-writer/references/hook-formulas.md +482 -0
- package/bundled-skills/llm-council/SKILL.md +4 -2
- package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package-lock.json +5 -6
- package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package.json +2 -3
- package/bundled-skills/markdown-rendering/SKILL.md +72 -0
- package/bundled-skills/matematico-tao/scripts/complexity_analyzer.py +14 -1
- package/bundled-skills/matematico-tao/scripts/dependency_graph.py +15 -2
- package/bundled-skills/mobile-design/scripts/mobile_audit.py +20 -6
- package/bundled-skills/monte-carlo-validation-notebook/scripts/resolve_dbt_schema.py +15 -2
- package/bundled-skills/multi-agent-architect/SKILL.md +1 -1
- package/bundled-skills/odoo-rpc-api/SKILL.md +2 -1
- package/bundled-skills/pci-compliance/SKILL.md +3 -1
- package/bundled-skills/pdf-official/scripts/create_validation_image.py +17 -3
- package/bundled-skills/pdf-official/scripts/extract_form_field_info.py +1 -1
- package/bundled-skills/personal-tool-builder/SKILL.md +1 -1
- package/bundled-skills/pi-custom-model/SKILL.md +68 -0
- package/bundled-skills/pi-web-search/SKILL.md +74 -0
- package/bundled-skills/playwright-skill/run.js +19 -1
- package/bundled-skills/pptx-official/ooxml/scripts/pack.py +30 -3
- package/bundled-skills/pptx-official/ooxml/scripts/unpack.py +16 -3
- package/bundled-skills/pptx-official/scripts/inventory.py +17 -4
- package/bundled-skills/pptx-official/scripts/rearrange.py +15 -2
- package/bundled-skills/pptx-official/scripts/replace.py +16 -3
- package/bundled-skills/product-manager-toolkit/scripts/customer_interview_analyzer.py +15 -1
- package/bundled-skills/production-code-audit/SKILL.md +1 -1
- package/bundled-skills/push-skill-to-github/SKILL.md +61 -0
- package/bundled-skills/rclone-cli/references/commands/rclone_completion_powershell.md +3 -2
- package/bundled-skills/read-all-adrs/SKILL.md +35 -0
- package/bundled-skills/remote-gpu-trainer/scripts/verify_local.py +14 -1
- package/bundled-skills/research-prompt/SKILL.md +63 -0
- package/bundled-skills/run-deep-swe/SKILL.md +120 -0
- package/bundled-skills/senior-architect/scripts/architecture_diagram_generator.py +15 -2
- package/bundled-skills/senior-architect/scripts/dependency_analyzer.py +15 -2
- package/bundled-skills/senior-architect/scripts/project_architect.py +15 -2
- package/bundled-skills/senior-frontend/scripts/bundle_analyzer.py +14 -1
- package/bundled-skills/senior-frontend/scripts/frontend_scaffolder.py +14 -1
- package/bundled-skills/senior-fullstack/scripts/code_quality_analyzer.py +15 -2
- package/bundled-skills/senior-fullstack/scripts/fullstack_scaffolder.py +15 -2
- package/bundled-skills/senior-fullstack/scripts/project_scaffolder.py +15 -2
- package/bundled-skills/setup-help/SKILL.md +50 -0
- package/bundled-skills/shodan-reconnaissance/SKILL.md +2 -1
- package/bundled-skills/short/SKILL.md +28 -0
- package/bundled-skills/skill-creator/scripts/init_skill.py +15 -2
- package/bundled-skills/skill-creator/scripts/package_skill.py +29 -12
- package/bundled-skills/skill-creator/scripts/quick_validate.py +14 -2
- package/bundled-skills/skill-creator-ms/SKILL.md +1 -1
- package/bundled-skills/skill-installer/scripts/install_skill.py +42 -8
- package/bundled-skills/skill-installer/scripts/package_skill.py +29 -17
- package/bundled-skills/skill-installer/scripts/validate_skill.py +37 -22
- package/bundled-skills/stripe-integration/SKILL.md +7 -3
- package/bundled-skills/swiftui-expert-skill/scripts/instruments_parser/xctrace.py +7 -1
- package/bundled-skills/swiftui-expert-skill/scripts/instruments_parser/xml_utils.py +7 -1
- package/bundled-skills/taisly-social-media-posting/SKILL.md +79 -0
- package/bundled-skills/technical-tutorials/SKILL.md +1 -1
- package/bundled-skills/telegram/scripts/setup_project.py +17 -2
- package/bundled-skills/time-ledger/SKILL.md +118 -0
- package/bundled-skills/trading-ledger/SKILL.md +121 -0
- package/bundled-skills/videodb/scripts/ws_listener.py +17 -4
- package/bundled-skills/voice-ai-development/SKILL.md +2 -1
- package/bundled-skills/vps-server-management/SKILL.md +72 -0
- package/bundled-skills/weaviate/scripts/weaviate_conn.py +20 -18
- package/bundled-skills/wgm/SKILL.md +137 -0
- package/bundled-skills/whatsapp-cloud-api/scripts/setup_project.py +16 -1
- package/bundled-skills/workorai/SKILL.md +137 -0
- package/bundled-skills/wp-site-health-auditor/SKILL.md +341 -0
- package/bundled-skills/wp-site-health-auditor/references/catalog.md +135 -0
- package/bundled-skills/writing-skills/render-graphs.js +13 -2
- package/bundled-skills/x-twitter-scraper/SKILL.md +3 -1
- package/bundled-skills/youtube-notetaker/scripts/serve.py +41 -31
- package/bundled-skills/youtube-notetaker/scripts/vtt_to_transcript.py +16 -2
- package/bundled-skills/youtube-notetaker/scripts/write_library_item.py +15 -1
- package/bundled-skills/youtube-transcript/SKILL.md +120 -0
- package/package.json +5 -1
- package/skills_index.json +786 -6
|
@@ -17,6 +17,19 @@ import sys
|
|
|
17
17
|
from datetime import datetime, timezone
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
|
|
20
|
+
|
|
21
|
+
def safe_user_path(path_value, base_dir="."):
|
|
22
|
+
"""Resolve a CLI path under the current workspace."""
|
|
23
|
+
if base_dir != ".":
|
|
24
|
+
raise ValueError("Custom base directories are not supported for CLI paths")
|
|
25
|
+
base_path = Path.cwd().resolve()
|
|
26
|
+
resolved_path = Path(path_value).expanduser().resolve()
|
|
27
|
+
try:
|
|
28
|
+
resolved_path.relative_to(base_path)
|
|
29
|
+
except ValueError as exc:
|
|
30
|
+
raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
|
|
31
|
+
return resolved_path
|
|
32
|
+
|
|
20
33
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
21
34
|
|
|
22
35
|
_db = None
|
|
@@ -55,11 +68,9 @@ def export_json(records: list, output_dir: Path, name: str) -> Path:
|
|
|
55
68
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
56
69
|
ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
57
70
|
path = output_dir / f"instagram_{name}_{ts}.json"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
f, ensure_ascii=False, indent=2,
|
|
62
|
-
)
|
|
71
|
+
payload = {"exported_at": datetime.now(timezone.utc).isoformat(), "total": len(records), "data": records}
|
|
72
|
+
with safe_user_path(path).open("w", encoding="utf-8") as f:
|
|
73
|
+
f.write(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
63
74
|
print(f"[JSON] {len(records)} registros ->{path}")
|
|
64
75
|
return path
|
|
65
76
|
|
|
@@ -68,7 +79,7 @@ def export_jsonl(records: list, output_dir: Path, name: str) -> Path:
|
|
|
68
79
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
69
80
|
ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
70
81
|
path = output_dir / f"instagram_{name}_{ts}.jsonl"
|
|
71
|
-
with open(
|
|
82
|
+
with safe_user_path(path).open("w", encoding="utf-8") as f:
|
|
72
83
|
for rec in records:
|
|
73
84
|
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
|
|
74
85
|
print(f"[JSONL] {len(records)} registros ->{path}")
|
|
@@ -82,7 +93,7 @@ def export_csv_file(records: list, output_dir: Path, name: str) -> Path:
|
|
|
82
93
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
83
94
|
ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
84
95
|
path = output_dir / f"instagram_{name}_{ts}.csv"
|
|
85
|
-
with open(
|
|
96
|
+
with safe_user_path(path).open("w", newline="", encoding="utf-8-sig") as f:
|
|
86
97
|
writer = csv.DictWriter(f, fieldnames=list(records[0].keys()), extrasaction="ignore")
|
|
87
98
|
writer.writeheader()
|
|
88
99
|
writer.writerows(records)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: interview-style-doc-building
|
|
3
|
+
description: "Build structured strategy documents by asking one question at a time and patching the file."
|
|
4
|
+
category: productivity
|
|
5
|
+
risk: critical
|
|
6
|
+
source: community
|
|
7
|
+
source_repo: davidondrej/skills
|
|
8
|
+
source_type: community
|
|
9
|
+
date_added: "2026-07-07"
|
|
10
|
+
author: davidondrej
|
|
11
|
+
tags: [documentation, interview, planning]
|
|
12
|
+
tools: [claude, codex]
|
|
13
|
+
license: "MIT"
|
|
14
|
+
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Interview-Style Doc Building
|
|
18
|
+
|
|
19
|
+
The user's preferred mode for creating durable strategic docs. AI does NOT propose content — AI asks one question, the user answers, AI patches the file, AI asks the next question. The file IS the conversation's output, updated incrementally.
|
|
20
|
+
|
|
21
|
+
## When to Use
|
|
22
|
+
|
|
23
|
+
- Building a new SSOT file (life priorities, life vision, principles, frameworks, ranked lists).
|
|
24
|
+
- Filling out a structured doc the user explicitly wants to author themselves.
|
|
25
|
+
- Quarterly/annual reviews where the user's words go into the file.
|
|
26
|
+
|
|
27
|
+
**NOT for:** day planning (use `day-plan`), task triage (`organize-tasks`), or anything where AI proposes content first.
|
|
28
|
+
|
|
29
|
+
## The Loop
|
|
30
|
+
|
|
31
|
+
1. **Create the file** with a skeleton (header, sections, "to be filled in" placeholders). Single `write_file` for the new file. After this, NEVER overwrite — only `patch`.
|
|
32
|
+
2. **Ask ONE question.** Concise. Specific. Single-faceted. Open-ended where possible.
|
|
33
|
+
3. **Wait for the answer.** Don't ask the next question yet.
|
|
34
|
+
4. **Patch the file** with the user's answer in the correct section.
|
|
35
|
+
5. **Re-ask** — next question, or follow-up if the answer was incomplete.
|
|
36
|
+
6. Repeat until the file is complete.
|
|
37
|
+
|
|
38
|
+
## Hard Rules
|
|
39
|
+
|
|
40
|
+
- **One question at a time.** Never dump multiple questions in a single message. The user has flagged this.
|
|
41
|
+
- **Patch, don't overwrite.** After the initial skeleton, use `patch` for every update. Never `write_file` to an existing doc.
|
|
42
|
+
- **Update the file BEFORE asking the next question.** Order: receive answer → patch file → ask next question. Not the reverse.
|
|
43
|
+
- **Lists from the user are UNORDERED SETS.** When the user lists items in response to "which X should we cover?" or "what are the Ys?", that is a SET, not a ranking. Never infer rank, priority, or sequence from the order they typed them. If you need ordering, ask explicitly: "Which of these is #1?"
|
|
44
|
+
- **Ask dynamics, not names.** When the user references a person, don't ask "who is X?" — ask about the role/dynamic.
|
|
45
|
+
- **No snark, no attitude, no filler.** Concise questions, concise acknowledgments.
|
|
46
|
+
- **No speculative additions.** Don't invent sections, edge cases, or "anything else?" prompts unless the user asks.
|
|
47
|
+
|
|
48
|
+
## Question Design
|
|
49
|
+
|
|
50
|
+
- **Domain-discovery, not confirmation.** "What wins against everything else?" — not "Is Business #1?"
|
|
51
|
+
- **Surface new reality.** Each question should pull out info AI doesn't already have.
|
|
52
|
+
- **Engine-move framing where applicable.** "What's the thing that, if true, makes the rest obvious?"
|
|
53
|
+
- **Concrete over abstract.** "What's #2 — the domain that wins against everything except #1?" beats "Tell me about your second priority."
|
|
54
|
+
|
|
55
|
+
## File Patching Pattern
|
|
56
|
+
|
|
57
|
+
After each answer:
|
|
58
|
+
1. Read the relevant section (if not already in context).
|
|
59
|
+
2. `patch` with `old_string` = placeholder or previous entry, `new_string` = updated content with the user's words preserved.
|
|
60
|
+
3. Confirm the diff. Move on.
|
|
61
|
+
|
|
62
|
+
For ranked lists, append one rank at a time:
|
|
63
|
+
```
|
|
64
|
+
1. **Business** — Q2 #1 goal: ...
|
|
65
|
+
2. **Health** — get below 81.0 kg, sleep 9h/day, ...
|
|
66
|
+
```
|
|
67
|
+
Each rank gets patched in as the user confirms it.
|
|
68
|
+
|
|
69
|
+
## Common Pitfalls
|
|
70
|
+
|
|
71
|
+
- **Assuming order from a set.** The user lists "A, B, C, D" → AI writes "1. A, 2. B, 3. C, 4. D" → the user flags it. ALWAYS confirm rank explicitly.
|
|
72
|
+
- **Asking too many questions at once.** Even bundling 2 violates the rule.
|
|
73
|
+
- **Overwriting the file** instead of patching specific sections — destroys prior content.
|
|
74
|
+
- **Adding AI-generated content** to fill out sections. Sections stay empty until the user provides the content.
|
|
75
|
+
- **Skipping the file update** between Q&A pairs — the doc falls out of sync.
|
|
76
|
+
|
|
77
|
+
## Pairing with Other Skills
|
|
78
|
+
|
|
79
|
+
- `day-plan` — different pattern (task triage), not interview-style.
|
|
80
|
+
- `organize-tasks` — Todoist-specific.
|
|
81
|
+
- `memory-management` — separate from this; persona/preferences go to memory.
|
|
82
|
+
|
|
83
|
+
## Limitations
|
|
84
|
+
|
|
85
|
+
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
|
|
86
|
+
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
|
|
@@ -18,6 +18,19 @@ import json
|
|
|
18
18
|
import sys
|
|
19
19
|
from datetime import datetime, timezone
|
|
20
20
|
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def safe_user_path(path_value, base_dir="."):
|
|
24
|
+
"""Resolve a CLI path under the current workspace."""
|
|
25
|
+
if base_dir != ".":
|
|
26
|
+
raise ValueError("Custom base directories are not supported for CLI paths")
|
|
27
|
+
base_path = Path.cwd().resolve()
|
|
28
|
+
resolved_path = Path(path_value).expanduser().resolve()
|
|
29
|
+
try:
|
|
30
|
+
resolved_path.relative_to(base_path)
|
|
31
|
+
except ValueError as exc:
|
|
32
|
+
raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
|
|
33
|
+
return resolved_path
|
|
21
34
|
from typing import List, Optional
|
|
22
35
|
|
|
23
36
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
@@ -31,13 +44,9 @@ def export_json(records: list, output_dir: Path, suffix: str = "") -> Path:
|
|
|
31
44
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
32
45
|
ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
33
46
|
path = output_dir / f"leiloeiros{suffix}_{ts}.json"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
f,
|
|
38
|
-
ensure_ascii=False,
|
|
39
|
-
indent=2,
|
|
40
|
-
)
|
|
47
|
+
payload = {"exported_at": datetime.now(timezone.utc).isoformat(), "total": len(records), "data": records}
|
|
48
|
+
with safe_user_path(path).open("w", encoding="utf-8") as f:
|
|
49
|
+
f.write(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
41
50
|
print(f"[JSON] {len(records)} registros → {path}")
|
|
42
51
|
return path
|
|
43
52
|
|
|
@@ -46,7 +55,7 @@ def export_jsonl(records: list, output_dir: Path, suffix: str = "") -> Path:
|
|
|
46
55
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
47
56
|
ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
48
57
|
path = output_dir / f"leiloeiros{suffix}_{ts}.jsonl"
|
|
49
|
-
with open(
|
|
58
|
+
with safe_user_path(path).open("w", encoding="utf-8") as f:
|
|
50
59
|
for rec in records:
|
|
51
60
|
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
|
|
52
61
|
print(f"[JSONL] {len(records)} registros → {path}")
|
|
@@ -62,7 +71,7 @@ def export_csv(records: list, output_dir: Path, suffix: str = "") -> Path:
|
|
|
62
71
|
ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
63
72
|
path = output_dir / f"leiloeiros{suffix}_{ts}.csv"
|
|
64
73
|
|
|
65
|
-
with open(
|
|
74
|
+
with safe_user_path(path).open("w", newline="", encoding="utf-8-sig") as f:
|
|
66
75
|
writer = csv.DictWriter(f, fieldnames=list(records[0].keys()), extrasaction="ignore")
|
|
67
76
|
writer.writeheader()
|
|
68
77
|
writer.writerows(records)
|
|
@@ -106,7 +115,7 @@ def main():
|
|
|
106
115
|
db = Database()
|
|
107
116
|
db.init()
|
|
108
117
|
|
|
109
|
-
output_dir =
|
|
118
|
+
output_dir = safe_user_path(args.output)
|
|
110
119
|
estados = [e.upper() for e in args.estado] if args.estado else None
|
|
111
120
|
|
|
112
121
|
if estados:
|
|
@@ -16,6 +16,20 @@ import sys
|
|
|
16
16
|
from typing import Dict, List, Any, Optional
|
|
17
17
|
from datetime import datetime
|
|
18
18
|
import html as html_module
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def safe_user_path(path_value, base_dir="."):
|
|
23
|
+
"""Resolve a CLI path under the current workspace."""
|
|
24
|
+
if base_dir != ".":
|
|
25
|
+
raise ValueError("Custom base directories are not supported for CLI paths")
|
|
26
|
+
base_path = Path.cwd().resolve()
|
|
27
|
+
resolved_path = Path(path_value).expanduser().resolve()
|
|
28
|
+
try:
|
|
29
|
+
resolved_path.relative_to(base_path)
|
|
30
|
+
except ValueError as exc:
|
|
31
|
+
raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
|
|
32
|
+
return resolved_path
|
|
19
33
|
|
|
20
34
|
|
|
21
35
|
def escape(text: str) -> str:
|
|
@@ -557,7 +571,7 @@ def main():
|
|
|
557
571
|
output = generate_html(config)
|
|
558
572
|
|
|
559
573
|
if args.output:
|
|
560
|
-
with
|
|
574
|
+
with safe_user_path(args.output).open("w") as f:
|
|
561
575
|
f.write(output)
|
|
562
576
|
print(f"Landing page written to {args.output}")
|
|
563
577
|
else:
|
|
@@ -127,10 +127,12 @@ If setup reports a missing API key:
|
|
|
127
127
|
|
|
128
128
|
```bash
|
|
129
129
|
# Option A: Add to shell profile (~/.zshrc or ~/.bashrc)
|
|
130
|
-
|
|
130
|
+
read -rsp "Linear API key: " LINEAR_API_KEY
|
|
131
|
+
echo
|
|
132
|
+
export LINEAR_API_KEY
|
|
131
133
|
|
|
132
134
|
# Option B: Add to Claude Code environment
|
|
133
|
-
|
|
135
|
+
printf 'LINEAR_API_KEY=%s\n' "$LINEAR_API_KEY" >> ~/.claude/.env
|
|
134
136
|
|
|
135
137
|
# Then reload your shell or restart Claude Code
|
|
136
138
|
```
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: linkedin-post-writer
|
|
3
|
+
description: "Draft LinkedIn posts from 16 tested hook formulas mapped to engagement goals (comments, reposts, likes, saves), with 2026 algorithm formatting rules and an AI-tell scrub pass before publishing."
|
|
4
|
+
category: marketing
|
|
5
|
+
risk: none
|
|
6
|
+
source: community
|
|
7
|
+
source_repo: sergebulaev/linkedin-skills
|
|
8
|
+
source_type: community
|
|
9
|
+
date_added: "2026-07-06"
|
|
10
|
+
author: sergebulaev
|
|
11
|
+
tags: [linkedin, copywriting, hooks, social-media, personal-brand, content-marketing]
|
|
12
|
+
tools: [claude, codex, cursor, gemini]
|
|
13
|
+
license: "MIT"
|
|
14
|
+
license_source: "https://github.com/sergebulaev/linkedin-skills/blob/main/LICENSE"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# LinkedIn Post Writer
|
|
18
|
+
|
|
19
|
+
## Overview
|
|
20
|
+
|
|
21
|
+
Drafts long-form LinkedIn posts using 16 hook formulas that were reverse-engineered from posts that outperformed their authors' baselines in 2025-2026, each with a reference engagement number. Instead of asking "what should I write", the workflow asks "what should this post earn" (comments, reposts, likes, or saves), shortlists 2-3 matching formulas, fills the chosen skeleton with the user's voice, then scrubs the draft for AI tells before it ships.
|
|
22
|
+
|
|
23
|
+
This is the flagship skill from [sergebulaev/linkedin-skills](https://github.com/sergebulaev/linkedin-skills), a 10-skill LinkedIn bundle (writer, humanizer, pre-publish audit, comment drafter, reply handler, hook extractor, content planner, profile optimizer, engager analytics, thread monitor) installable as a Claude Code or Codex plugin. This standalone version covers the drafting workflow; scheduling and publishing automation live in the full bundle.
|
|
24
|
+
|
|
25
|
+
## When to Use This Skill
|
|
26
|
+
|
|
27
|
+
- Use when the user says "write me a LinkedIn post about X"
|
|
28
|
+
- Use when the user has a topic and a rough angle but needs a hook and structure
|
|
29
|
+
- Use when the user wants to pick from proven post formats instead of improvising
|
|
30
|
+
- Use when a draft exists but the hook is weak and needs a formula-based rebuild
|
|
31
|
+
- Not for replying to comments or optimizing profiles; this skill only drafts posts
|
|
32
|
+
|
|
33
|
+
## How It Works
|
|
34
|
+
|
|
35
|
+
### Step 1: Gather inputs
|
|
36
|
+
|
|
37
|
+
Collect: topic, angle, target audience (founders, operators, marketers), desired length (short 300-500, medium 900-1,300, or long 1,500-1,900 characters), and any raw material the user already has (numbers, anecdotes, names).
|
|
38
|
+
|
|
39
|
+
### Step 2: Pick the formula by engagement goal first
|
|
40
|
+
|
|
41
|
+
Ask (or infer) what the post should earn, then shortlist:
|
|
42
|
+
|
|
43
|
+
| Goal | Earned by | Formulas |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| Comments | questions, contrarian takes, vulnerability | F4 Time-Anchor Confession, F10 Contrarian + Receipts, F12 Permission Slip, F9 Curiosity-Gap |
|
|
46
|
+
| Reposts | quotable maxims, tributes, "X isn't Y" distinctions | F14 Named Gratitude, F2 R.I.P. Obituary, F8 Paid-vs-Free Reversal |
|
|
47
|
+
| Likes | emotional stories, celebrations, status-strip | F11 Emotional Cold-Open, F13 Bait-and-Switch Reversal, F16 Status-Strip Humility |
|
|
48
|
+
| Saves | simplifications, exact how-to, frameworks | F15 Explain-to-Kids, F7 Odd-Precision Money Ledger, F8 Paid-vs-Free Reversal |
|
|
49
|
+
|
|
50
|
+
The full set of 16, with reference engagement:
|
|
51
|
+
|
|
52
|
+
| Code | Formula | Reference | Best for |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| F1 | Platform Risk Anaphora | 4,240 eng | Category and platform-risk arguments |
|
|
55
|
+
| F2 | R.I.P. Obituary | 3,822 eng | Era-ending claims, industry pivots |
|
|
56
|
+
| F3 | Year-over-Year Pivot | 494 eng, 3.74x baseline | Identity shifts, founder reflection |
|
|
57
|
+
| F4 | Time-Anchor Confession | 1,519+ eng | Vulnerability, voice reset |
|
|
58
|
+
| F5 | Self-Proving Meta | 1,082 eng, 435 comments | Commitments and tests in public |
|
|
59
|
+
| F6 | Comment-Gate Lead Magnet | 717-3,008 eng | List building (max once a month) |
|
|
60
|
+
| F7 | Odd-Precision Money Ledger | 1,755 eng, 9.4x baseline | Build logs, cost breakdowns |
|
|
61
|
+
| F8 | Paid-vs-Free Reversal | 550 eng, 19.64x baseline | Framework giveaways |
|
|
62
|
+
| F9 | Curiosity-Gap Teaser | 306 eng, 4.25x baseline | Surprise and behind-the-scenes stories |
|
|
63
|
+
| F10 | Contrarian + Historical Receipts | 3,083 eng | Sacred-cow takes backed by history |
|
|
64
|
+
| F11 | Emotional Cold-Open | high raw reach | Real stories with emotional stakes |
|
|
65
|
+
| F12 | Permission Slip | comment-heavy | Encouragement to a discouraged audience |
|
|
66
|
+
| F13 | Bait-and-Switch Reversal | high raw reach | Bad-news framing that turns into an upgrade |
|
|
67
|
+
| F14 | Named Gratitude / Tribute | repost-heavy | Thanking mentors, teams, departing colleagues |
|
|
68
|
+
| F15 | Explain-to-Kids | save-heavy | Demystifying jargon into a reference post |
|
|
69
|
+
| F16 | Status-Strip Humility | like-heavy | Senior voices trading prestige for warmth |
|
|
70
|
+
|
|
71
|
+
Important caveat: F1-F10 references are engagement counts or format multipliers against the author's own baseline; F11-F16 references are raw corpus reach, often inflated by a famous author or a reshare. The two groups measure different things, so never rank formulas across groups by number.
|
|
72
|
+
|
|
73
|
+
The full skeletons for all 16 formulas are bundled with this skill in [references/hook-formulas.md](references/hook-formulas.md), along with per-formula warnings and the "Never do" list.
|
|
74
|
+
|
|
75
|
+
### Step 3: Draft the post
|
|
76
|
+
|
|
77
|
+
Read the chosen formula's skeleton from the bundled [references/hook-formulas.md](references/hook-formulas.md) and fill it with the user's voice and material, respecting the 2026 formatting rules:
|
|
78
|
+
|
|
79
|
+
- Hook lands in the first 210 characters (before the "... see more" fold)
|
|
80
|
+
- 900-1,300 characters is the sweet spot for text posts
|
|
81
|
+
- Double line-breaks between ideas, never walls of text
|
|
82
|
+
- 0-2 hashtags, placed at the end
|
|
83
|
+
- No external links in the body (put links in the first comment)
|
|
84
|
+
- Prefer "How I" over "How to": first-person experience hooks outperform generic instruction 2-3x
|
|
85
|
+
- Put one specific number in the first sentence ($873.47 beats $900; 40,000 beats "a lot")
|
|
86
|
+
|
|
87
|
+
### Step 4: Scrub AI tells
|
|
88
|
+
|
|
89
|
+
Before showing the draft: strip em dashes, AI vocabulary ("game-changer", "deep dive", "delve"), rule-of-three lists without receipts, and generic openers like "In today's fast-paced world". Add human fingerprints: at least one specific number, one named entity, and one first-person concrete detail per 100 words. Vary sentence length aggressively (mix 3-word and 25-word sentences).
|
|
90
|
+
|
|
91
|
+
### Step 5: Present the result
|
|
92
|
+
|
|
93
|
+
Show the user: formula used, full draft, character count, and a suggested posting window (Tuesday to Thursday, 7:30-9:00 AM local time performs best for B2B audiences).
|
|
94
|
+
|
|
95
|
+
## Examples
|
|
96
|
+
|
|
97
|
+
### Example 1: Founder build-log (F7 Odd-Precision Money Ledger)
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
User: write a post about what my bootstrapped SaaS actually costs to run
|
|
101
|
+
Agent: Goal check: this reads like a saves play (people screenshot cost
|
|
102
|
+
breakdowns). Best fit is F7 Odd-Precision Money Ledger (9.4x baseline).
|
|
103
|
+
Draft hook:
|
|
104
|
+
|
|
105
|
+
"My SaaS costs $412.83 a month to run. Here is every line item."
|
|
106
|
+
|
|
107
|
+
Then the ledger: hosting $94.20, email $35.00, monitoring $18.63...
|
|
108
|
+
exact numbers only, totals that actually add up, one lesson at the end.
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Example 2: Goal-first selection
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
User: I want a post that gets real comments, topic: why I stopped doing demos
|
|
115
|
+
Agent: Comment-earners are F4 Confession, F10 Contrarian, F12 Permission Slip.
|
|
116
|
+
For "I stopped doing X" the strongest is F10 Contrarian + Receipts:
|
|
117
|
+
open with the unpopular claim, back it with 2 historical parallels,
|
|
118
|
+
close with a question that forces side-picking. Reference: 3,083 eng.
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Best Practices
|
|
122
|
+
|
|
123
|
+
- ✅ Pick the formula by engagement goal first, topic second
|
|
124
|
+
- ✅ Lead with a real failure or a specific number in the first 3 lines
|
|
125
|
+
- ✅ Include one moment of genuine vulnerability or concrete stakes; pure insight posts underperform in 2026
|
|
126
|
+
- ❌ Don't blend two hook formulas in one post; it dilutes both
|
|
127
|
+
- ❌ Don't use F5 Self-Proving Meta unless the user will actually keep the promise
|
|
128
|
+
- ❌ Don't pair F7 Money Ledger with rounded or invented numbers; readers notice
|
|
129
|
+
- ❌ Don't open with an all-caps line ("THIS CHANGED EVERYTHING")
|
|
130
|
+
- ❌ Don't frame LinkedIn as inferior inside a LinkedIn post
|
|
131
|
+
|
|
132
|
+
## Limitations
|
|
133
|
+
|
|
134
|
+
- Reference engagement numbers describe the 2025-2026 corpus the formulas were extracted from; they are priors, not guarantees, and LinkedIn's ranking changes over time.
|
|
135
|
+
- The skill drafts text posts; it does not generate images, carousels, or video scripts.
|
|
136
|
+
- This standalone version does not schedule or publish. Scheduling, comment drafting, reply handling, and engagement analytics require the full bundle from the source repo.
|
|
137
|
+
- Voice quality depends on the raw material the user provides; a formula cannot invent authentic anecdotes, and the skill should ask for real details rather than fabricate them.
|
|
138
|
+
|
|
139
|
+
## Common Pitfalls
|
|
140
|
+
|
|
141
|
+
- **Problem:** The draft sounds like every other AI-written LinkedIn post.
|
|
142
|
+
**Solution:** Run Step 4 ruthlessly. Cut em dashes, cut "game-changer" vocabulary, and force one concrete first-person detail per 100 words.
|
|
143
|
+
- **Problem:** The hook is buried in paragraph two.
|
|
144
|
+
**Solution:** The first 210 characters must carry the hook; everything before the fold decides the expand rate.
|
|
145
|
+
- **Problem:** Comparing F11's raw reach to F8's 19.64x multiplier and picking F11 "because the number is bigger".
|
|
146
|
+
**Solution:** The columns measure different things. Match formula to goal and topic, not to the largest number.
|
|
147
|
+
- **Problem:** Post gets reach but zero comments.
|
|
148
|
+
**Solution:** The formula was picked for the wrong goal. Comment-earners end with a question or a side-picking claim, not a summary.
|
|
149
|
+
|
|
150
|
+
## Related Skills
|
|
151
|
+
|
|
152
|
+
- `@linkedin-content-generator` - broader LinkedIn content suite (carousels, newsletters, calendars)
|
|
153
|
+
- `@linkedin-profile-optimizer` - profile and authority optimization rather than post drafting
|
|
154
|
+
- `@social-post-writer-seo` - multi-platform social copy when LinkedIn is not the only target
|
|
155
|
+
|
|
156
|
+
## Additional Resources
|
|
157
|
+
|
|
158
|
+
- [Source repo with all 16 formula skeletons and worked examples](https://github.com/sergebulaev/linkedin-skills)
|
|
159
|
+
- [Full 10-skill bundle install (Claude Code / Codex plugin)](https://github.com/sergebulaev/linkedin-skills#install)
|