Skill: dayunyan/academic-writer (version 0.1.0)

--- name: academic-writer description: "Professional LaTeX writing assistant. Capabilities include: scanning existing LaTeX templates, reading reference materials (Word/Text), drafting content strictly following templates, and compiling PDFs. Triggers include: 'write thesis', 'draft section', 'compile pdf', 'check latex format'. Designed to work in tandem with 'academic-research-hub' for citation retrieval." license: Proprietary permissions: - shell:exec env: PYTHON_CMD: python3 --- # Academic Writer & LaTeX Composer A comprehensive agent skill for orchestrating academic paper writing in a WSL2/Linux environment. It manages the lifecycle from template analysis to PDF compilation. ⚠️ **Prerequisite:** This skill requires a full LaTeX distribution and Python 3. ## Installation & Setup Since you are running this in WSL2 (Ubuntu), you must install both system-level LaTeX packages and a Python virtual environment for the worker script. ### 1. System Dependencies (LaTeX) Open your WSL terminal and run: ```bash # Update package lists sudo apt-get update # Install the full TeX Live distribution (Required for all templates) # Warning: This download is approx 4GB-7GB sudo apt-get install texlive-full # Install latexmk for automated compilation sudo apt-get install latexmk ``` ### 2. Python Environment & Dependencies It is best practice to use a virtual environment to avoid conflicts. ```bash # Go to your skill directory cd ~/.openclaw/skills/academic-writer # Create a virtual environment python3 -m venv venv # Activate the environment source venv/bin/activate # Install required Python packages # python-docx: For reading Word documents pip install python-docx ``` --- ## Quick Reference | Task | Tool Command | |------|--------------| | **Analyze Project** | `scan_template` | | **Read Notes** | `read_reference` | | **Draft Content** | `write_latex` | | **Generate PDF** | `compile_pdf` | | **Find Citations** | *Delegate to `academic-research-hub`* | --- ## System Instructions & Workflow **Role:** You are an expert Academic Writer and LaTeX Typesetter. **Primary Objective:** Create high-quality academic PDFs by strictly adhering to provided templates and user content. ### Core Logic Steps #### 1. Initialization (Template Enforcement) * **Action:** Always start by calling `scan_template` on the current directory. * **Logic:** * **If a template exists (e.g., IEEE, ACM, local .cls files):** You MUST respect the class structure. Do not change the preamble unless necessary for a new package. * **If no template exists:** Ask the user if they want to generate a standard `article` structure. #### 2. Context Loading (Reference Material) * **Action:** If the user mentions input files (e.g., "use my notes.docx" or "reference draft.txt"), call `read_reference`. * **Logic:** Use this content as the "Ground Truth" for your writing. Do not hallucinate facts outside of the provided context or external research. #### 3. Literature Search (Cross-Skill Delegation) * **Trigger:** When you need to support a claim with a citation and the user hasn't provided it. * **Action:** **DO NOT** make up citations. Instead, instruct the agent to use the **`academic-research-hub`** skill. * **Protocol:** 1. Pause writing. 2. Invoke search (e.g., "Find papers on X using academic-research-hub"). 3. Get the BibTeX. 4. Resume writing: Append BibTeX to the `.bib` file using `write_latex` (mode='a') and use `\cite{key}` in the text. #### 4. Writing & Compilation * **Action:** Use `write_latex` to create `.tex` files. * **Action:** After finishing a significant section, call `compile_pdf`. * **Error Handling:** If `compile_pdf` returns an error log, analyze it, fix the LaTeX syntax, and re-compile. --- ## Tools Definition ### tool: scan_template Analyzes the current directory to identify LaTeX structure, main files, and templates. - **command**: `${PYTHON_CMD} scripts/writer_tools.py scan_template {{directory}}` - **params**: - `directory`: (string) Path to scan. Default is ".". ### tool: read_reference Reads raw text from reference files. Supports `.docx`, `.txt`, `.tex`, `.md`. - **command**: `${PYTHON_CMD} scripts/writer_tools.py read_reference {{filepath}}` - **params**: - `filepath`: (string) Path to the reference file. ### tool: write_latex Writes content to a specific file. Can overwrite or append. - **command**: `${PYTHON_CMD} scripts/writer_tools.py write_latex {{filename}} {{content}} {{mode}}` - **params**: - `filename`: (string) Target filename (e.g., "introduction.tex"). - `content`: (string) Raw LaTeX content. - `mode`: (string) "w" for overwrite, "a" for append. Default is "w". ### tool: compile_pdf Compiles the project using `latexmk`. Returns success message or error logs. - **command**: `${PYTHON_CMD} scripts/writer_tools.py compile_pdf {{main_file}}` - **params**: - `main_file`: (string) The root TeX file (e.g., "main.tex"). --- ## Common Workflows ### 1. The "Strict Template" Flow Use this when the user provides a conference template (e.g., IEEEtrans). 1. **User:** "Draft the intro using `notes.docx` in this folder." 2. **Agent:** Calls `scan_template` -> Detects `main.tex` (IEEE class). 3. **Agent:** Calls `read_reference` -> Gets content from `notes.docx`. 4. **Agent:** Calls `write_latex` -> Writes `intro.tex` following IEEE style. 5. **Agent:** Calls `write_latex` -> Updates `main.tex` to `\input{intro}`. 6. **Agent:** Calls `compile_pdf` -> Checks for layout errors. ### 2. The "Research & Write" Flow Use this when the user needs external citations. 1. **User:** "Write a paragraph about LLM Agents and cite recent papers." 2. **Agent:** *Thinking:* "I need citations." 3. **Agent:** **Calls `academic-research-hub`** (e.g., search arXiv for "LLM Agents 2025"). 4. **Agent:** Receives BibTeX data. 5. **Agent:** Calls `write_latex` (mode='a') -> Appends to `references.bib`. 6. **Agent:** Calls `write_latex` -> Writes paragraph with `\cite{...}`. 7. **Agent:** Calls `compile_pdf`. --- ## Troubleshooting ### Compilation Failures * **Error:** `latexmk: command not found` * **Fix:** Ensure you ran `sudo apt-get install latexmk`. * **Error:** `! LaTeX Error: File 'article.cls' not found.` * **Fix:** Ensure you ran `sudo apt-get install texlive-full`. * **Error:** `! Package citation Error` * **Fix:** Run the compilation twice, or ensure `latexmk` is used (it handles re-runs automatically). ### Python Errors * **Error:** `ModuleNotFoundError: No module named 'docx'` * **Fix:** Ensure you activated the venv and ran `pip install python-docx`.

path: scripts/writer_tools.py
content: import os
import sys
import subprocess
import json
import glob
try:
    from docx import Document
except ImportError:
    Document = None

def read_reference(file_path):
    """读取参考资料"""
    if not os.path.exists(file_path):
        return f"Error: File {file_path} not found."
    
    try:
        if file_path.endswith('.docx'):
            if Document is None:
                return "Error: python-docx not installed. Run `pip install python-docx`."
            doc = Document(file_path)
            full_text = [para.text for para in doc.paragraphs]
            return '\n'.join(full_text)
        else:
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                return f.read()
    except Exception as e:
        return f"Error reading file: {str(e)}"

def scan_template(directory="."):
    """扫描 LaTeX 结构"""
    tex_files = glob.glob(os.path.join(directory, "*.tex"))
    bib_files = glob.glob(os.path.join(directory, "*.bib"))
    
    main_file = None
    structure = {}
    
    for f_path in tex_files:
        with open(f_path, 'r', encoding='utf-8', errors='ignore') as f:
            content = f.read()
            # 简单启发式查找主文件
            if "\\documentclass" in content and "\\begin{document}" in content:
                main_file = os.path.basename(f_path)
            # 截取前 800 字符供 LLM 理解模板头部
            structure[os.path.basename(f_path)] = content[:800] + "\n...(truncated)"

    return json.dumps({
        "detected_main_file": main_file,
        "tex_files": [os.path.basename(f) for f in tex_files],
        "bib_files": [os.path.basename(f) for f in bib_files],
        "file_previews": structure
    }, ensure_ascii=False)

def write_latex_content(filename, content, mode='w'):
    """写入文件"""
    try:
        with open(filename, mode, encoding='utf-8') as f:
            f.write(content)
        return f"Success: Wrote {len(content)} chars to {filename}"
    except Exception as e:
        return f"Error writing: {str(e)}"

def compile_pdf(main_file):
    """编译 PDF"""
    if not main_file:
        return "Error: No main file specified."
    
    # 检查 latexmk 是否存在
    if subprocess.call(["which", "latexmk"], stdout=subprocess.DEVNULL) != 0:
        return "Error: latexmk not found. Please install texlive-full."

    try:
        # -interaction=nonstopmode: 不因错误暂停
        # -pdf: 生成 PDF
        result = subprocess.run(
            ['latexmk', '-pdf', '-interaction=nonstopmode', main_file],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            timeout=60 # 防止死循环
        )
        
        if result.returncode == 0:
            return f"Success! PDF generated: {main_file.replace('.tex', '.pdf')}"
        else:
            # 提取最后部分的错误日志
            logs = result.stdout + "\n" + result.stderr
            return f"Compilation Failed. Error Log Tail:\n{logs[-1500:]}"
    except Exception as e:
        return f"Execution Error: {str(e)}"

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python3 writer_tools.py <command> [args]")
        sys.exit(1)

    cmd = sys.argv[1]
    args = sys.argv[2:]

    if cmd == "read_reference":
        print(read_reference(args[0] if args else ""))
    elif cmd == "scan_template":
        print(scan_template(args[0] if args else "."))
    elif cmd == "write_latex":
        # write_latex filename content mode
        filename = args[0]
        content = args[1]
        mode = args[2] if len(args) > 2 else 'w'
        print(write_latex_content(filename, content, mode))
    elif cmd == "compile_pdf":
        print(compile_pdf(args[0] if args else ""))
    else:
        print(f"Unknown command: {cmd}")

Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: suspicious | SkillSpector: clean (LOW)