Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
Scientify 是一个 OpenClaw 插件,提供 AI 驱动的科研工作流自动化功能。

**核心组件:**
- `src/tools/` - 工具实现(arxiv_search, arxiv_download, openalex_search, unpaywall_download, github_search, paper_browser)
- `src/tools/` - 工具实现(arxiv_search, openalex_search, paper_download, paper_browser)
- `src/utils/` - 通用工具(security.ts 输入校验)
- `src/commands.ts` - 聊天命令处理
- `skills/` - 技能定义(随 npm 包发布)
- `index.ts` - 插件入口
Expand Down Expand Up @@ -119,19 +120,30 @@ scientify/
├── README.zh.md # 中文文档
├── src/
│ ├── commands.ts # 聊天命令
│ ├── openclaw.d.ts # 类型声明
│ ├── types.ts # 类型定义
│ ├── cli/
│ │ └── research.ts # CLI 入口(init/delete/list 项目)
│ ├── commands/
│ │ └── metabolism-status.ts # 新陈代谢状态命令
│ ├── hooks/
│ │ ├── inject-skill.ts # Skill 注入 hook
│ │ └── cron-skill-inject.ts # Cron skill 注入 hook
│ ├── templates/
│ │ └── bootstrap.ts # 项目初始化模板
│ ├── utils/
│ │ └── security.ts # 输入校验(路径遍历防护、ID 格式校验)
│ └── tools/
│ ├── arxiv-search.ts # ArXiv 搜索工具
│ ├── arxiv-download.ts # ArXiv 下载工具(含速率限制)
│ ├── openalex-search.ts # OpenAlex 跨学科搜索
│ ├── unpaywall-download.ts # Unpaywall OA PDF 下载
│ ├── github-search-tool.ts # GitHub 搜索工具
│ └── paper-browser.ts # 论文分页浏览工具
│ ├── paper-download.ts # 论文下载(arXiv .tex/PDF + DOI via Unpaywall)
│ ├── paper-browser.ts # 论文分页浏览工具
│ └── result.ts # 工具结果辅助函数
├── skills/
│ ├── idea-generation/
│ │ ├── SKILL.md
│ │ └── references/idea-template.md
│ ├── research-collect/SKILL.md # 文献搜索 → 筛选 → 下载 → 聚类
│ ├── metabolism/SKILL.md # 新陈代谢循环(Day 0 + Day 1+)
│ ├── research-collect/SKILL.md # 文献搜索 → 筛选 → 下载 → 聚类
│ ├── research-pipeline/SKILL.md # 编排器,通过 sessions_spawn 调度以下 5 个 skill
│ ├── research-survey/SKILL.md # 深度论文分析 + 方法对比
│ ├── research-plan/SKILL.md # 四部分实现计划
Expand Down
15 changes: 3 additions & 12 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Driven by multi-agent iteration: the orchestrator holds hypotheses and all accum
│ │──→│ edit them too │
│ arxiv_search │ └──────────────────────────────┘
│ openalex_search │
github_search
paper_download
│ paper_browser │
│ code_executor │
└──────────────────────────┘
Expand Down Expand Up @@ -121,7 +121,7 @@ The agents' hands and eyes:
| Tool | Capability |
|------|-----------|
| `arxiv_search` / `openalex_search` | Search academic papers (arXiv + cross-disciplinary) |
| `github_search` | Search open-source code implementations |
| `paper_download` | Download papers by arXiv ID (.tex source with PDF fallback) or DOI (open-access PDF via Unpaywall). Input validation prevents shell injection. |
| `paper_browser` | Paginated paper reading, avoids context overflow |
| `code_executor` | Execute experiment code in `uv`-isolated environment |

Expand Down Expand Up @@ -276,7 +276,6 @@ Check status anytime:
| Skill | Description |
|-------|-------------|
| **write-review-paper** | Draft a review/survey paper from project research outputs. |
| **research-subscription** | Create/list/remove scheduled Scientify jobs via `scientify_cron_job` (research digests or plain reminders). |

</details>

Expand All @@ -286,14 +285,9 @@ Check status anytime:
| Tool | Description |
|------|-------------|
| `arxiv_search` | Search arXiv papers. Returns metadata (title, authors, abstract, ID). Supports sorting by relevance/date and date filtering. |
| `arxiv_download` | Batch download papers by arXiv ID. Prefers .tex source files (PDF fallback). |
| `openalex_search` | Search cross-disciplinary academic papers via OpenAlex API. Returns DOI, authors, citation count, OA status. |
| `openreview_lookup` | Lookup OpenReview evidence by title/ID/forum. Returns decision, review rating/confidence aggregates, and review summaries. |
| `unpaywall_download` | Download open access PDFs by DOI via Unpaywall API. Non-OA papers are silently skipped. |
| `github_search` | Search GitHub repositories. Returns repo name, description, stars, URL. Supports language filtering and sorting. |
| `paper_download` | Download papers by arXiv ID (prefers .tex source, PDF fallback) or DOI (open-access PDF via Unpaywall). Validates all identifiers to prevent injection. Max 20 papers per call with rate limiting. |
| `paper_browser` | Paginated browsing of large paper files (.tex/.md) to avoid context overflow. |
| `scientify_cron_job` | Manage scheduled Scientify jobs (`upsert`/`list`/`remove`). |
| `scientify_literature_state` | Persistent incremental state for subscriptions: dedupe, record, feedback, and status inspection. |

</details>

Expand All @@ -308,9 +302,6 @@ Check status anytime:
| `/projects` | List all projects |
| `/project-switch <id>` | Switch active project |
| `/project-delete <id>` | Delete a project |
| `/research-subscribe ...` | Create/update scheduled Scientify jobs |
| `/research-subscriptions` | Show your scheduled Scientify jobs |
| `/research-unsubscribe [job-id]` | Remove your scheduled Scientify jobs |

</details>

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Scientify 采用**新陈代谢模式**——持续地摄入、消化、沉淀、
│ │──→│ │
│ arxiv_search │ └──────────────────────────────┘
│ openalex_search │
github_search
paper_download
│ paper_browser │
│ code_executor │
└──────────────────────────┘
Expand Down Expand Up @@ -121,7 +121,7 @@ Agent 的手和眼:
| 工具 | 能力 |
|------|------|
| `arxiv_search` / `openalex_search` | 搜索学术论文(arXiv + 跨学科) |
| `github_search` | 搜索开源代码实现 |
| `paper_download` | 下载论文:arXiv ID(优先 .tex 源文件,PDF 兜底)或 DOI(通过 Unpaywall 获取 OA PDF)。内置输入校验防止注入攻击。 |
| `paper_browser` | 分页精读论文,避免上下文溢出 |
| `code_executor` | 在 `uv` 隔离环境中执行实验代码 |

Expand Down
4 changes: 4 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
} from "./src/commands.js";
import { createArxivSearchTool } from "./src/tools/arxiv-search.js";
import { createOpenAlexSearchTool } from "./src/tools/openalex-search.js";
import { createPaperDownloadTool } from "./src/tools/paper-download.js";
import { createPaperBrowserTool } from "./src/tools/paper-browser.js";
import { createSkillInjectionHook } from "./src/hooks/inject-skill.js";
import { createCronSkillInjectionHook } from "./src/hooks/cron-skill-inject.js";
import { registerResearchCli } from "./src/cli/research.js";
Expand All @@ -23,6 +25,8 @@ export default definePluginEntry({
// Register tools
api.registerTool(createArxivSearchTool());
api.registerTool(createOpenAlexSearchTool());
api.registerTool(createPaperDownloadTool());
api.registerTool(createPaperBrowserTool());

// Register chat commands (bypass LLM)
api.registerCommand({
Expand Down
1 change: 0 additions & 1 deletion openclaw.plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"skills/research-review",
"skills/research-experiment",
"skills/research-collect",
"skills/paper-download",
"skills/write-review-paper",
"skills/metabolism"
]
Expand Down
2 changes: 1 addition & 1 deletion skills/idea-generation/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ arxiv_search({ query: "{user_topic}", max_results: 10 })
openalex_search({ query: "{user_topic}", max_results: 10 })
```

2. **Download papers:** 按 /paper-download 的方式下载到 `papers/`
2. **Download papers:** 使用 `paper_download` 工具下载到 `papers/`

3. **Clone reference repos (optional):**
```bash
Expand Down
2 changes: 1 addition & 1 deletion skills/metabolism/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ openalex_search({

合并结果,按 arXiv ID / DOI 去重,**跳过 `processed_ids` 中已有的论文**。

按 /paper-download 的方式下载新论文到 `papers/`(arXiv 优先 .tex 源文件,DOI 通过 Unpaywall 获取 OA PDF)。
使用 `paper_download` 工具下载新论文到 `papers/`(arXiv 优先 .tex 源文件,DOI 通过 Unpaywall 获取 OA PDF)。

### Step 2: Read(阅读)

Expand Down
61 changes: 0 additions & 61 deletions skills/paper-download/SKILL.md

This file was deleted.

4 changes: 2 additions & 2 deletions skills/research-collect/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ openalex_search({ query: "<term>", max_results: 20 })

#### 2.3 下载论文

按 /paper-download 的方式下载论文到 `papers/`。
使用 `paper_download` 工具下载论文到 `papers/`。

**完成一个检索词后,再进行下一个。** 这样避免上下文被大量搜索结果污染。

Expand Down Expand Up @@ -140,5 +140,5 @@ mv "papers/2401.12345" "papers/data-driven/"
|----------------|---------|
| `arxiv_search` | 搜索 arXiv 论文 |
| `openalex_search` | 搜索跨学科论文(覆盖更广) |
| /paper-download | 下载论文(arXiv .tex/PDF、DOI via Unpaywall) |
| paper_download | 下载论文(arXiv .tex/PDF、DOI via Unpaywall) |
| `gh search repos "query"` | 搜索 GitHub 仓库 |
5 changes: 5 additions & 0 deletions src/cli/research.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import { renderBootstrapMd, renderSoulMd, renderAgentsMd } from "../templates/bootstrap.js";
import { validateProjectId, ensureWithinDirectory } from "../utils/security.js";

const OPENCLAW_HOME = path.join(os.homedir(), ".openclaw");
const OPENCLAW_CONFIG = path.join(OPENCLAW_HOME, "openclaw.json");
Expand Down Expand Up @@ -141,8 +142,10 @@ function listResearchProjects(): ResearchProject[] {
}

function initProject(id: string, pluginSkillsDir: string): void {
validateProjectId(id);
const agentId = `research-${id}`;
const workspace = path.join(OPENCLAW_HOME, `workspace-${agentId}`);
ensureWithinDirectory(workspace, OPENCLAW_HOME);

// Check if workspace already exists
if (fs.existsSync(workspace)) {
Expand Down Expand Up @@ -244,8 +247,10 @@ function showStatus(id: string): void {
}

function deleteProject(id: string): void {
validateProjectId(id);
const agentId = `research-${id}`;
const workspace = path.join(OPENCLAW_HOME, `workspace-${agentId}`);
ensureWithinDirectory(workspace, OPENCLAW_HOME);

// Remove workspace
if (fs.existsSync(workspace)) {
Expand Down
10 changes: 6 additions & 4 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as fs from "node:fs";
import * as path from "node:path";
import * as os from "node:os";
import type { PluginCommandContext, PluginCommandResult } from "./types.js";
import { ensureWithinDirectory } from "./utils/security.js";

const OPENCLAW_HOME = path.join(os.homedir(), ".openclaw");

Expand All @@ -20,10 +21,11 @@ function listResearchAgents(): ResearchAgent[] {
const agents = (config.agents as { list?: Array<{ id: string; workspace?: string }> })?.list ?? [];
return agents
.filter((a) => a.id.startsWith("research-"))
.map((a) => ({
id: a.id,
workspace: (a.workspace ?? `~/.openclaw/workspace-${a.id}`).replace("~", os.homedir()),
}));
.map((a) => {
const workspace = (a.workspace ?? `~/.openclaw/workspace-${a.id}`).replace("~", os.homedir());
ensureWithinDirectory(workspace, OPENCLAW_HOME);
return { id: a.id, workspace };
});
} catch {
return [];
}
Expand Down
Loading