
Paper Assembly
- 1 installs
- 255 repo stars
- Updated February 27, 2026
- lingzhi227/claude-research-skills
This is a copy of paper-assembly by lingzhi227 - installs and ranking accrue to the original listing.
Helps with ai & agent building tasks.
About
paper-assembly is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- paper-assembly
- AI & Agent Building
- AI-coding skill
Paper Assembly by the numbers
- 1 all-time installs (skills.sh)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/lingzhi227/claude-research-skills --skill paper-assemblyAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 255 |
| Last updated | February 27, 2026 |
| Repository | lingzhi227/claude-research-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Paper Assembly
Orchestrate the entire paper pipeline end-to-end with state management and checkpointing.
Input
$0— Paper project directory or paper plan
References
- Orchestration patterns and state management:
~/.claude/skills/paper-assembly/references/orchestration-patterns.md
Scripts
Check pipeline completeness
python ~/.claude/skills/paper-assembly/scripts/assembly_checker.py --dir paper/ --output checkpoint.json
python ~/.claude/skills/paper-assembly/scripts/assembly_checker.py --dir paper/ --verboseScans paper directory, checks 9 pipeline phases, reports missing artifacts, suggests next steps.
Workflow
Step 1: Assess Current State
1. Scan the paper directory for existing artifacts 2. Identify which phases are complete vs pending 3. Build a dependency graph of remaining work
Step 2: Execute Pipeline Phases
Run phases in dependency order:
| Phase | Skill | Input | Output |
|---|---|---|---|
| 1. Literature | literature-search, literature-review | Topic | Knowledge base, BibTeX |
| 2. Planning | research-planning | Knowledge base | Paper structure, task list |
| 3. Code | experiment-code | Plan | Training/eval pipeline |
| 4. Experiments | experiment-design | Code | Results JSON/CSV |
| 5. Figures | figure-generation | Results | PNG figures |
| 6. Tables | table-generation | Results | LaTeX tables |
| 7. Writing | paper-writing-section | All above | main.tex sections |
| 8. Citations | citation-management | Draft | references.bib |
| 9. Formatting | latex-formatting | Draft | Formatted LaTeX |
| 10. Compilation | paper-compilation | All | |
| 11. Review | self-review | Review scores |
Step 3: State Propagation
After each phase completes: 1. Save output artifacts to the paper directory 2. Propagate results to downstream phases 3. Update the progress checkpoint file
Step 4: Quality Gates
Before proceeding to the next phase:
- Verify all required outputs exist
- Check for consistency (e.g., all cited keys in .bib)
- Validate figures/tables match experimental results
Step 5: Final Assembly
1. Merge all sections into main.tex 2. Verify all \includegraphics files exist 3. Verify all \cite keys exist in .bib 4. Compile to PDF 5. Run self-review for quality check
Orchestration Patterns
Sequential Pipeline (AI-Scientist)
generate_ideas → experiments → writeup → reviewMulti-Agent State Broadcasting (AgentLaboratory)
# Propagate results to all downstream agents
set_agent_attr("dataset_code", code)
set_agent_attr("results", results_json)Copilot Mode (AgentLaboratory)
Human can intervene at any phase boundary for review/correction.
Checkpoint Format
{
"project": "paper-name",
"phases_completed": ["literature", "planning", "code"],
"current_phase": "experiments",
"artifacts": {
"literature": "knowledge_base.json",
"plan": "research_plan.json",
"code": "experiments/",
"results": null
},
"last_updated": "2024-01-15T10:30:00Z"
}Rules
- Never skip phases — each depends on previous outputs
- Save checkpoints after every phase completion
- Human review is recommended at phase boundaries
- All numbers in the paper must trace to actual experiment logs
- Re-run downstream phases if upstream changes
Related Skills
- Upstream: all other skills (this is the orchestrator)
- Downstream: paper-compilation, self-review
- See also: research-planning
Paper Assembly Orchestration Patterns
Extracted from AI-Scientist (launch_scientist.py), AI-Researcher (main_ai_researcher.py), and AgentLaboratory (ai_lab_repo.py).
Pattern 1: Sequential Pipeline (AI-Scientist)
# launch_scientist.py main loop:
# Phase 1: Idea Generation
ideas = generate_ideas(
base_dir=base_dir,
client=client,
model=model,
max_num_generations=MAX_NUM_GENERATIONS,
num_reflections=NUM_REFLECTIONS,
)
# Phase 2: Novelty Check
for idea in ideas:
novel = check_idea_novelty(
idea=idea,
max_num_iterations=10,
)
if not novel:
continue
# Phase 3: Experiments
success = perform_experiments(idea, base_dir)
if not success:
continue
# Phase 4: Writeup
perform_writeup(idea, base_dir, client, model)
# Phase 5: Review
review = perform_review(
paper_path=f"{base_dir}/latex/paper.pdf",
model=model,
num_reflections=5,
num_reviews_ensemble=5,
)Pattern 2: Multi-Agent State Broadcasting (AgentLaboratory)
# ai_lab_repo.py — propagate results to all agents
def set_agent_attr(self, attr_name, value):
"""Broadcast an attribute to all agents in the lab."""
for agent in self.agents:
setattr(agent, attr_name, value)
# Usage during pipeline:
lab.set_agent_attr("literature_review", lit_review_text)
lab.set_agent_attr("research_plan", plan_json)
lab.set_agent_attr("dataset_code", code_str)
lab.set_agent_attr("experiment_results", results_dict)
lab.set_agent_attr("paper_sections", sections_dict)
# Each agent can access shared state:
class PhdAgent:
def write_section(self, section_name):
# Can reference self.experiment_results, self.literature_review, etc.
passPattern 3: FlowModule Caching (AI-Researcher)
# main_ai_researcher.py — cache each agent's output
class FlowModule:
"""Base class for cacheable pipeline stages."""
def __init__(self, cache_dir):
self.cache_dir = cache_dir
def run(self, input_data):
cache_key = self._compute_cache_key(input_data)
cached = self._load_cache(cache_key)
if cached is not None:
return cached
result = self._execute(input_data)
self._save_cache(cache_key, result)
return result
def _execute(self, input_data):
raise NotImplementedError
# Pipeline with caching:
modules = [
PlanAgent(cache_dir="cache/plan"),
SurveyAgent(cache_dir="cache/survey"),
CodeAgent(cache_dir="cache/code"),
ExperimentAgent(cache_dir="cache/experiment"),
WriteupAgent(cache_dir="cache/writeup"),
]
state = initial_input
for module in modules:
state = module.run(state) # Cached if previously computedPattern 4: Copilot Mode Checkpoints (AgentLaboratory)
# Human intervention at phase boundaries
PHASES = [
"literature_review",
"plan_formulation",
"data_preparation",
"running_experiments",
"results_interpretation",
"report_writing",
"report_refinement",
]
for phase in PHASES:
print(f"\n{'='*50}")
print(f"Phase: {phase}")
print(f"{'='*50}\n")
result = execute_phase(phase, state)
if copilot_mode:
print(f"\nPhase '{phase}' complete.")
print(f"Result preview: {result[:500]}...")
action = input("Continue / Edit / Redo / Skip? ")
if action == "Edit":
result = get_human_edits(result)
elif action == "Redo":
result = execute_phase(phase, state)
elif action == "Skip":
continue
state[phase] = result
save_checkpoint(state, f"checkpoint_{phase}.json")Checkpoint File Format
{
"project_name": "my-paper",
"created_at": "2024-01-15T10:00:00Z",
"last_updated": "2024-01-15T14:30:00Z",
"current_phase": "report_writing",
"phases": {
"literature_review": {
"status": "completed",
"output_file": "literature_review.json",
"completed_at": "2024-01-15T10:30:00Z"
},
"plan_formulation": {
"status": "completed",
"output_file": "research_plan.json",
"completed_at": "2024-01-15T11:00:00Z"
},
"data_preparation": {
"status": "completed",
"output_file": "data_prep.py",
"completed_at": "2024-01-15T12:00:00Z"
},
"running_experiments": {
"status": "completed",
"output_file": "results.json",
"completed_at": "2024-01-15T13:30:00Z"
},
"results_interpretation": {
"status": "completed",
"output_file": "analysis.json",
"completed_at": "2024-01-15T14:00:00Z"
},
"report_writing": {
"status": "in_progress",
"output_file": null,
"started_at": "2024-01-15T14:00:00Z"
},
"report_refinement": {
"status": "pending"
}
},
"artifacts": {
"bib_file": "references.bib",
"figures": ["Figure_1.png", "Figure_2.png"],
"tables": ["table_comparison.tex"],
"main_tex": "main.tex"
}
}Phase Dependency Graph
literature_review
↓
plan_formulation
↓
data_preparation ──→ running_experiments
↓
results_interpretation
↓
report_writing ──→ report_refinement
↑ ↓
figure_generation self_review
table_generation ↓
citation_management final_compilationError Recovery
# If a phase fails, recover from last checkpoint:
def recover_from_checkpoint(checkpoint_path):
state = load_checkpoint(checkpoint_path)
# Find the last completed phase
last_completed = None
for phase in PHASES:
if state["phases"][phase]["status"] == "completed":
last_completed = phase
else:
break
# Resume from next phase
resume_idx = PHASES.index(last_completed) + 1 if last_completed else 0
for phase in PHASES[resume_idx:]:
state = execute_phase(phase, state)
save_checkpoint(state)
return state#!/usr/bin/env python3
"""Check paper pipeline completeness and report missing artifacts.
Scans a paper directory, checks which pipeline phases are complete
(literature, code, figures, tables, bib, sections), reports missing
artifacts, and suggests next steps.
Self-contained: uses only stdlib.
Usage:
python assembly_checker.py --dir paper/ --output checkpoint.json
python assembly_checker.py --dir paper/
python assembly_checker.py --dir paper/ --verbose
"""
import argparse
import glob
import json
import os
import re
import sys
PIPELINE_PHASES = [
{
"name": "literature",
"description": "Literature search and review",
"artifacts": ["*.jsonl", "knowledge_base.*", "papers.bib"],
"patterns": ["literature", "papers", "references"],
},
{
"name": "planning",
"description": "Research plan and paper structure",
"artifacts": ["research_plan.*", "plan.*", "outline.*"],
"patterns": ["plan", "outline"],
},
{
"name": "code",
"description": "Experiment code and scripts",
"artifacts": ["*.py", "*.sh", "train.*", "eval.*"],
"patterns": ["code", "scripts", "src", "experiments"],
},
{
"name": "results",
"description": "Experimental results",
"artifacts": ["results.*", "*.csv", "metrics.*", "logs/"],
"patterns": ["results", "output", "logs"],
},
{
"name": "figures",
"description": "Generated figures",
"artifacts": ["*.png", "*.pdf", "*.eps"],
"patterns": ["figures", "figs", "plots", "images"],
},
{
"name": "tables",
"description": "LaTeX tables",
"artifacts": ["*table*.tex", "*results*.tex"],
"patterns": ["tables"],
},
{
"name": "bibliography",
"description": "BibTeX bibliography",
"artifacts": ["*.bib"],
"patterns": ["."],
},
{
"name": "sections",
"description": "Paper sections (LaTeX)",
"artifacts": ["*.tex"],
"patterns": ["sections", "."],
},
{
"name": "compilation",
"description": "Compiled PDF",
"artifacts": ["*.pdf"],
"patterns": ["."],
},
]
EXPECTED_SECTIONS = [
"abstract", "introduction", "related", "method",
"experiment", "result", "conclusion", "appendix",
]
def find_artifacts(base_dir: str, phase: dict) -> list[str]:
"""Find artifacts for a pipeline phase."""
found = []
search_dirs = [base_dir]
for pattern_dir in phase["patterns"]:
candidate = os.path.join(base_dir, pattern_dir)
if os.path.isdir(candidate):
search_dirs.append(candidate)
for search_dir in search_dirs:
for artifact_pattern in phase["artifacts"]:
if artifact_pattern.endswith("/"):
# Check for directory
dpath = os.path.join(search_dir, artifact_pattern.rstrip("/"))
if os.path.isdir(dpath):
found.append(dpath)
else:
matches = glob.glob(os.path.join(search_dir, artifact_pattern))
found.extend(matches)
# Deduplicate
return sorted(set(found))
def check_tex_sections(base_dir: str) -> dict:
"""Check which paper sections exist in .tex files."""
tex_files = glob.glob(os.path.join(base_dir, "**/*.tex"), recursive=True)
all_tex = ""
for tf in tex_files:
try:
with open(tf, encoding="utf-8", errors="replace") as f:
all_tex += f.read() + "\n"
except Exception:
pass
found_sections = set()
for match in re.finditer(r"\\section\*?\{([^}]+)\}", all_tex):
name = match.group(1).lower().strip()
for expected in EXPECTED_SECTIONS:
if expected in name:
found_sections.add(expected)
if re.search(r"\\begin\{abstract\}", all_tex):
found_sections.add("abstract")
return {
"found": sorted(found_sections),
"missing": sorted(set(EXPECTED_SECTIONS[:7]) - found_sections),
"tex_files": [os.path.relpath(f, base_dir) for f in tex_files],
}
def check_citations(base_dir: str) -> dict:
"""Check citation status."""
tex_files = glob.glob(os.path.join(base_dir, "**/*.tex"), recursive=True)
bib_files = glob.glob(os.path.join(base_dir, "**/*.bib"), recursive=True)
cite_keys = set()
for tf in tex_files:
try:
with open(tf, encoding="utf-8", errors="replace") as f:
content = f.read()
for match in re.findall(r"\\cite[a-z]*\{([^}]+)\}", content):
for key in match.split(","):
cite_keys.add(key.strip())
except Exception:
pass
bib_keys = set()
for bf in bib_files:
try:
with open(bf, encoding="utf-8", errors="replace") as f:
content = f.read()
bib_keys.update(re.findall(r"@\w+\{([^,]+),", content))
except Exception:
pass
return {
"cited": len(cite_keys),
"in_bib": len(bib_keys),
"missing": sorted(cite_keys - bib_keys),
"unused": len(bib_keys - cite_keys),
}
def check_figures(base_dir: str) -> dict:
"""Check figure status."""
tex_files = glob.glob(os.path.join(base_dir, "**/*.tex"), recursive=True)
fig_refs = set()
for tf in tex_files:
try:
with open(tf, encoding="utf-8", errors="replace") as f:
content = f.read()
fig_refs.update(re.findall(r"\\includegraphics(?:\[.*?\])?\{([^}]+)\}", content))
except Exception:
pass
missing_figs = []
for fig in fig_refs:
fig_path = os.path.join(base_dir, fig)
found = os.path.exists(fig_path)
if not found:
for ext in [".png", ".pdf", ".jpg", ".eps"]:
if os.path.exists(fig_path + ext):
found = True
break
if not found:
missing_figs.append(fig)
return {
"referenced": len(fig_refs),
"missing": missing_figs,
}
def suggest_next_steps(phase_status: dict) -> list[str]:
"""Suggest next steps based on pipeline status."""
steps = []
for phase_name, status in phase_status.items():
if not status["complete"]:
if phase_name == "literature":
steps.append("Run literature search: use literature-search skill")
elif phase_name == "planning":
steps.append("Create research plan: use research-planning skill")
elif phase_name == "code":
steps.append("Write experiment code: use experiment-code skill")
elif phase_name == "results":
steps.append("Run experiments to generate results")
elif phase_name == "figures":
steps.append("Generate figures: use figure-generation skill")
elif phase_name == "tables":
steps.append("Generate tables: use table-generation skill")
elif phase_name == "bibliography":
steps.append("Add bibliography: use citation-management skill")
elif phase_name == "sections":
steps.append("Write paper sections: use paper-writing-section skill")
elif phase_name == "compilation":
steps.append("Compile paper: use paper-compilation skill")
return steps
def main():
parser = argparse.ArgumentParser(description="Check paper pipeline completeness")
parser.add_argument("--dir", required=True, help="Paper directory")
parser.add_argument("--output", "-o", help="Output JSON checkpoint file")
parser.add_argument("--verbose", action="store_true", help="Show detailed artifacts")
args = parser.parse_args()
if not os.path.isdir(args.dir):
print(f"Error: {args.dir} is not a directory", file=sys.stderr)
sys.exit(1)
phase_status = {}
completed = 0
for phase in PIPELINE_PHASES:
artifacts = find_artifacts(args.dir, phase)
is_complete = len(artifacts) > 0
phase_status[phase["name"]] = {
"complete": is_complete,
"artifacts": [os.path.relpath(a, args.dir) for a in artifacts],
"count": len(artifacts),
}
if is_complete:
completed += 1
# Detailed checks
section_info = check_tex_sections(args.dir)
citation_info = check_citations(args.dir)
figure_info = check_figures(args.dir)
next_steps = suggest_next_steps(phase_status)
report = {
"directory": os.path.abspath(args.dir),
"phases_completed": completed,
"phases_total": len(PIPELINE_PHASES),
"completion_pct": round(100 * completed / len(PIPELINE_PHASES)),
"phases": phase_status,
"sections": section_info,
"citations": citation_info,
"figures": figure_info,
"next_steps": next_steps,
}
# Print summary
print(f"Paper Pipeline Status: {args.dir}")
print(f" Completion: {completed}/{len(PIPELINE_PHASES)} phases ({report['completion_pct']}%)\n")
for name, status in phase_status.items():
icon = "+" if status["complete"] else "-"
print(f" [{icon}] {name}: {status['count']} artifacts")
if args.verbose and status["artifacts"]:
for a in status["artifacts"][:5]:
print(f" {a}")
if section_info["missing"]:
print(f"\n Missing sections: {', '.join(section_info['missing'])}")
if citation_info["missing"]:
print(f" Missing citations: {len(citation_info['missing'])}")
if figure_info["missing"]:
print(f" Missing figures: {', '.join(figure_info['missing'])}")
if next_steps:
print(f"\n Next steps:")
for step in next_steps:
print(f" -> {step}")
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
json.dump(report, f, indent=2, ensure_ascii=False)
print(f"\n Checkpoint saved to {args.output}", file=sys.stderr)
if __name__ == "__main__":
main()