Article Production Toolchain
Companion skill for professional-writer. Handles the research, citation, visualization, media, and multi-publication infrastructure layers that feed the writer. The writer skill handles voice, structure, and prose — this skill handles everything that goes into the piece before and after the words.
Load alongside professional-writer for any article that needs: citations with verified sources, publication-quality charts, embedded media, or cross-publication management.
When To Load
- Any article that cites sources (papers, studies, data)
- Any article with charts, graphs, or data visualization
- Any article needing embedded images or media
- Setting up or managing multiple publications simultaneously
- Building an editorial pipeline that spans several outlets
Skip for: pure opinion pieces, personal essays, or articles where the writer's voice is the only asset.
Layer 1: Research Gathering
Source Types and Tools
| Source type | Tool | Command/Pattern |
|---|---|---|
| Academic papers | arxiv skill (Hermes-native, loads in-context) OR curl fallback |
arxiv skill: loaded alongside this skill, then search by keyword. CLI fallback: curl -s "http://export.arxiv.org/api/query?search_query=all:TERM&max_results=10" (API is HTTP-only — approve the security prompt) |
| Blogs/RSS | blogwatcher skill |
Monitor relevant feeds for current content |
| Reddit discussions | reddit-data-extraction skill |
Extract threads from domain subs. Use Arctic Shift API. |
| Hacker News | Algolia API | curl -s "https://hn.algolia.com/api/v1/search?query=TOPIC&tags=story&hitsPerPage=10" |
| GitHub projects | github-repo-discovery skill |
Find tools, datasets, and reference implementations |
| Existing notes | obsidian skill |
Search user's vault at /mnt/c/Users/Lenovo/Desktop/work/ |
PITFALL: The arxiv CLI binary does not exist — it's a Hermes skill that gets loaded into context, not a standalone command. If the arxiv skill isn't loaded, use the curl fallback against the arXiv API. The API endpoint is HTTP-only (not HTTPS), which triggers Hermes's security prompt — approve it.
Research Output Format
Save all gathered sources to a structured research file:
# Research: [Article Title]
## Key Papers
- [Title] ([Year]) — [One-line finding]. DOI: [link]
- [Title] ([Year]) — [One-line finding]. arXiv: [id]
## Data Points
- [Statistic] — Source: [publication, year, page/URL]
- [Statistic] — Source: [publication, year, page/URL]
## Competing Views
- [Author/Outlet]: [Position summary] — [Why they hold it]
- [Author/Outlet]: [Position summary] — [Why they hold it]
## Relevant Threads
- HN: [title] ([points] pts, [comments] comments) — [key takeaway]
- Reddit r/[sub]: [title] — [key takeaway]
## Tools & Repos
- [owner/repo] (★[stars]) — [relevance to article]
Layer 2: Citation Pipeline
Quick Start: Which Tool When
| Situation | Tool | Why |
|---|---|---|
| Building a .bib library from scratch | JabRef/jabref | GUI, imports from DOI/arXiv/ISBN, exports BibTeX/BibLaTeX |
| CLI/scriptable workflows | papis/papis | Command-line, Python API, git-backed |
| Finding papers on a topic | findpapers | Searches multiple academic databases, outputs CSV |
| Automated manuscript with live citations | manubot/manubot | Markdown → HTML/PDF with auto-resolved citations from DOIs/URLs/arXiv IDs |
| Quick bibliography formatting | pubs/pubs | CLI, lightweight, BibTeX-native |
Citation Workflow
Step 1: Discover papers
# Using findpapers (Python CLI)
pip install findpapers
findpapers search "ketamine depression mechanisms" --limit 30 --output results.csv
# Using arxiv skill (Hermes-native)
# Load arxiv skill, search by keyword
Step 2: Collect to bibliography
# Using papis (CLI-based)
papis add --from doi 10.1038/s41586-023-12345-6
papis add --from arxiv 2301.12345
papis add --from url https://example.com/paper
# Using JabRef (GUI-based)
# Launch: java -jar JabRef-*.jar
# Drag-and-drop PDFs, auto-extract metadata
Step 3: Insert citations in article
For markdown-based articles (Substack, blog):
Ketamine's rapid antidepressant effects are mediated through mTOR pathway activation
[@berman2000; @zorumski2023]. Recent meta-analyses confirm effect sizes of d=0.8-1.2
for single-dose protocols [@xu2024].
For manubot-based articles (scientific publishing):
Ketamine's rapid antidepressant effects are mediated through mTOR pathway activation
[@doi:10.1016/s0006-3223(99)00230-9; @arxiv:2301.12345].
Step 4: Generate formatted bibliography
# Using pandoc with .bib file
pandoc article.md --bibliography=references.bib --citeproc -o article-with-refs.md
# Using manubot (auto-resolves from inline DOIs/URLs)
manubot process --content-directory content --output-directory output
Citation Quality Checklist
Before finalizing any article with citations:
- Every factual claim has a source
- Sources are primary (studies, papers, official data) not secondary (blog posts about studies)
- Publication dates are within 3 years unless citing foundational work
- DOIs resolve (test with
curl -I https://doi.org/10.xxx/xxxx) - No circular citations (source A cites source B, but you're using A as proof of B's claim)
- Contrarian or disconfirming evidence is cited alongside supporting evidence
Layer 3: Publication-Quality Data Visualization
Tool Selection by Chart Type
| Chart type | Tool | Why | Code pattern |
|---|---|---|---|
| Bar, line, scatter, area | Apache ECharts | Beautiful defaults, responsive, interactive. Best for publication embedding. | JSON config object, no build step |
| Custom/unusual viz | D3.js | Maximum control. Network graphs, force layouts, custom geometries. | SVG manipulation, steeper learning curve |
| Statistical plots | Python matplotlib/seaborn → PNG | Familiar, precise, reproducible. | Generate PNG, embed in article |
| Interactive dashboards | Streamlit | Turn Python scripts into web apps. Good for article supplements. | streamlit run app.py |
| Real-time data | Grafana | For articles about live metrics or monitoring data | Screenshot from Grafana instance |
ECharts Workflow (Recommended for Most Articles)
- Write chart config as JSON
- Render in browser or screenshot via headless Chromium
- Save as high-res PNG (at least 1200px wide for Substack)
- Embed in article with alt text and source caption
// Example: Comparative bar chart
{
title: { text: 'Antidepressant Response Rates by Protocol' },
tooltip: {},
xAxis: { data: ['Placebo', 'SSRI', 'Ketamine IV', 'Ketamine IM', 'Psilocybin'] },
yAxis: { name: 'Response Rate (%)' },
series: [{
type: 'bar',
data: [30, 47, 71, 65, 68],
itemStyle: { color: '#6366f1' }
}]
}
Rendering for article embedding:
# Option A: Save as standalone HTML for interactive (link from article)
cat > chart.html << 'EOF'
<!DOCTYPE html><html><head>
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
</head><body><div id="chart" style="width:800px;height:500px;"></div>
<script>/* ... echarts config ... */</script></body></html>
EOF
# Option B: Screenshot via Chromium for static PNG
# Use Playwright or Puppeteer to capture
D3.js for Custom Visualizations
Use when ECharts built-in chart types don't fit. Common in:
- Network/graph visualizations
- Custom interactive explainers
- Force-directed layouts
- Animated transitions between states
Design Standards for All Charts
- Dark theme preferred for tech/science publications (matches Substack dark mode)
- Font: Inter for labels, JetBrains Mono for code/numeric data
- Color palette: Use 6-color palette — #6366f1 (indigo), #ec4899 (pink), #10b981 (emerald), #f59e0b (amber), #3b82f6 (blue), #ef4444 (red)
- Minimum resolution: 1200px wide for Substack (they upscale)
- Always include: title, axis labels with units, source line, data date range
- Never: 3D charts (distort data), pie charts with >5 slices, dual y-axes without clear labeling
Layer 4: Media & Image Retrieval
Finding Images for Articles
For scientific/technical images:
# PubMed Central images (open access)
# Search PMC, filter by CC-BY license
# Wikimedia Commons (freely licensed)
curl -s "https://commons.wikimedia.org/w/api.php?action=query&list=search&srsearch=TOPIC&format=json"
# Flickr Creative Commons
curl -s "https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=KEY&text=TOPIC&license=4,5,6,7,8&format=json"
For general illustration/storytelling:
# Unsplash (free, no attribution required)
# Use their API or direct search
# Pexels (free, no attribution required)
# Use their API
Reverse image search (verify source/origin):
# dessant/search-by-image browser extension
# Right-click → "Search by Image" → 30+ engines
Image Attribution Format
Every image in the article must include:

*Caption explaining what the image shows. Source: [Creator/Organization] ([License])*
Image Quality Standards
- Minimum 1200px wide for Substack
- PNG for diagrams/charts, JPEG for photographs
- Compress photographs (quality 85) — Substack has file size limits
- Keep diagrams under 500KB
Layer 5: Multi-Publication Orchestration
Publication Manifest
For managing multiple publications, create a master manifest at ~/writing/publications.yaml:
publications:
- id: research-collective
name: "Research Collective"
platform: substack
url: https://researchcollective.substack.com
niche: "Nootropics, research chemicals, neurochemistry"
cadence: weekly
voice_profile: "scott-alexander"
free_tier: "Deep-dive articles, literature reviews"
paid_tier: "Protocol guides, sourcing directories, compound analyses"
- id: transhumanism-digest
name: "Transhumanism Digest"
platform: substack
url: https://transhumanismdigest.substack.com
niche: "BCI, longevity, gene therapy, AI-human integration"
cadence: biweekly
voice_profile: "dwarkesh-patel"
free_tier: "Trend analysis, paper summaries"
paid_tier: "Investment memos, technology deep-dives"
- id: personal-blog
name: "Personal Blog"
platform: ghost
url: https://lucadominguez.com
niche: "Building in public, agent workflows, experiments"
cadence: as-written
voice_profile: "default"
free_tier: "Everything"
Editorial Calendar
For each publication, maintain a forward-looking calendar at ~/writing/{pub-id}/calendar.md:
# Editorial Calendar: Research Collective
## July 2026
| Week | Article | Status | Research | Citations | Charts | Media |
|------|---------|--------|-----------|-----------|--------|-------|
| Jul 20 | Ketamine mechanisms update | Drafting | Done | 12 sources | 3 charts | 2 images |
| Jul 27 | Peptide sourcing guide v2 | Research | In progress | — | — | — |
## August 2026
| Week | Article | Status |
|------|---------|--------|
| Aug 3 | Novel nootropic patent review | Planned |
| Aug 10 | — (buffer week) | — |
| Aug 17 | RC safety protocols update | Planned |
| Aug 24 | Community compound survey results | Planned |
Cross-Publication Content Strategy
Repurpose, don't duplicate:
- A research finding can be a deep-dive in one pub and a shorter angle piece in another
- Same data, different framing: "Here's what this means for nootropics users" vs "Here's what this means for longevity research"
- Shared research folder, pub-specific drafts
Content tiers across publications:
Research (shared) →
├─ Research Collective: Deep-dive + protocol implications
├─ Transhumanism Digest: Future trajectory + investment angle
└─ Personal Blog: How I researched this + tooling used
Batch Production Mode
When filling multiple slots across publications, use parallel subagents:
professional-writer loaded for article A (Research Collective)
professional-writer loaded for article B (Transhumanism Digest)
Each subagent gets: its publication's voice profile, the shared research folder, and specific angle instructions.
Quality Consistency Across Publications
Every article across every publication must pass the same gate:
- Citations verified (DOIs resolve, sources are primary)
- Charts meet design standards (see Layer 3)
- Humanization pass complete (see professional-writer Phase 4)
- Read-aloud check (no AI rhythm)
- Title earns the click (specific, surprising, or useful)
- Publication voice profile applied correctly
Layer 6: Obsidian Integration
Vault Layout for Publications
{Vault}/Publications/
├── Publications Hub.md ← Master dashboard
├── publications.yaml ← Manifest (from Layer 5)
│
├── research-collective/
│ ├── Publication Hub.md ← Pub-specific dashboard
│ ├── Editorial Calendar.md
│ ├── Voice Profile.md ← This pub's voice parameters
│ ├── Articles/
│ │ ├── 2026-07-20-ketamine-mechanisms/
│ │ │ ├── research.md
│ │ │ ├── sources.bib
│ │ │ ├── draft-v1.md
│ │ │ ├── final.md
│ │ │ └── charts/
│ │ └── ...
│ ├── Playbooks/ ← Paid content
│ └── Assets/ ← Shared images, templates
│
├── transhumanism-digest/
│ └── ...
│
└── Shared Research/ ← Cross-publication research
├── nootropics-literature.md
├── longevity-clinical-trials.md
└── bci-patent-tracker.md
Git Workflow for Articles
# After creating/updating article in Obsidian vault
cd /mnt/c/Users/Lenovo/Desktop/work
git.exe add "Publications/research-collective/Articles/2026-07-20-ketamine-mechanisms/"
git.exe commit -m "article: ketamine mechanisms update - draft 1"
git.exe push origin main
PITFALL: On WSL, use git.exe (Windows git) not git (Linux git) for repos on /mnt/c/. The Linux git on NTFS filesystems is slow and can corrupt the index.
Quick Reference: Tool by Article Phase
| Phase | Tool | Key command |
|---|---|---|
| Research | arxiv skill | Search papers |
| blogwatcher skill | Monitor feeds | |
| reddit-data-extraction skill | Extract discussions | |
| Algolia HN API | curl search |
|
| Citation | findpapers | findpapers search "..." |
| papis | papis add --from doi ... |
|
| JabRef | GUI for .bib management | |
| manubot | Auto-citation from markdown | |
| Charts | ECharts | JSON config → HTML or PNG |
| D3.js | Custom SVG viz | |
| Streamlit | Interactive supplement | |
| Media | search-by-image | Reverse image lookup |
| Wikimedia API | Free licensed images | |
| Unsplash/Pexels | Stock photography | |
| Publishing | subskill: substack-publishing | Email or browser |
| himalaya CLI | Email-to-Substack | |
| Obsidian vault | Git-backed content | |
| Multi-pub | publications.yaml | Manifest |
| Editorial calendars | Per-pub planning |
Layer 7: Email Delivery
When the user wants the article emailed directly (vs published to Substack), use Gmail SMTP via Python. See references/email-delivery.md for the full script and prerequisites.
Quick pattern:
python3 << 'PYEOF'
import smtplib, os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
env = {}
with open(os.path.expanduser('~/.hermes/.env')) as f:
for line in f:
line = line.strip()
if line and '=' in line:
k, v = line.split('=', 1)
env[k] = v.strip().strip('"').strip("'")
msg = MIMEMultipart()
msg['Subject'] = 'Article: TITLE'
msg['From'] = env['EMAIL_ADDRESS']
msg['To'] = env['EMAIL_ADDRESS']
with open('/path/to/article.md') as f:
msg.attach(MIMEText(f.read(), 'plain'))
s = smtplib.SMTP('smtp.gmail.com', 587, timeout=15)
s.starttls()
s.login(env['EMAIL_ADDRESS'], env['EMAIL_PASSWORD'])
s.sendmail(env['EMAIL_ADDRESS'], env['EMAIL_ADDRESS'], msg.as_string())
s.quit()
print("SENT")
PYEOF
Requires: EMAIL_ADDRESS and EMAIL_PASSWORD (Gmail App Password, not account password) in ~/.hermes/.env.
PITFALLS
Citation DOI resolution is slow over VPN/proxy. Run citation lookups without proxy routing. If behind a VPN, temporarily route
curlthrough direct connection.ECharts requires JavaScript rendering. It doesn't produce static PNGs natively. Use a headless browser (Playwright/Puppeteer) or the ECharts export server for programmatic screenshots. For simple charts, matplotlib+seaborn → PNG is faster.
papis and JabRef conflict on .bib format. Pick one and stick with it per publication. papis uses its own library format but can export .bib. JabRef works natively with .bib. Don't mix them on the same library.
Image licenses matter for publication. A CC-BY image on Wikimedia is fine. An image you found via reverse image search on someone's blog is not — even if
search-by-imagefound it. Always verify license before embedding.Multi-publication voice bleed. When writing for two publications in the same session, reload the voice profile between pieces. The
professional-writerskill's voice parameters persist in memory — reset them explicitly between publications.Substack image compression. Substack compresses images aggressively. Upload at 2x the display size (2400px wide if the column is 1200px) and let them downscale. PNG for diagrams, JPEG quality 95 for photos.
Git on /mnt/c/ from WSL is slow. Use
git.exenotgit. Commits on large vaults can take 30+ seconds — usebackground=truewithnotify_on_complete=true.Matplotlib works in direct
terminal()but notexecute_codesandbox. The sandbox environment doesn't have matplotlib installed. When generating charts, usepython3 << 'PYEOF' ... PYEOFin a directterminal()call — the system Python has matplotlib. Theexecute_codesandbox is fine for gh API calls (though seegithub-repo-discoverypitfall #8 about auto-parsed dicts).