CLI-first Research Assistant Agent for AI Researchers
ARH turns daily research workflows — "reading papers, searching code, running experiments, writing summaries" — into an Agent runtime with tool calling, context management, approval gates, and persistent sessions. CLI-first, with optional Telegram and other channels. All data stored locally (~/.arh/), your conversations, memories, and API keys never leave your machine.
| Plan / Execute Hard-binding | Default mode only allows read-only tools. Write operations must go through planning + approval — no silent file modifications. |
| Three-layer Memory | Regex + LLM auto-extract user preferences / research directions; BM25 index for cross-session recall; LLM writes 4-section reflection summary at session end, auto-injected next time. |
| Skill Self-learning | Successful complex tasks automatically prompt to save as reusable Skill (requires user approval). Invoke via /skill or let LLM call directly. |
| Multi-LLM + Fallback | OpenAI / Anthropic / Ollama one-command switch; automatic fallback to backup models on failure with cooldown. |
| Auto Context Compression | When tokens exceed budget, LLM auto-summarizes old conversations, preserving system prompt + recent N turns + tool_call pairs. |
| Checkpoint & Resume | Session snapshots anytime, --resume to restore. No context loss on interruption. |
| Multi-channel Gateway | Hub-Spoke architecture: CLI / Telegram available; Feishu / WeChat in development. FastAPI exposes HTTP interface. |
| Research-specific Tools | arXiv / HuggingFace / GitHub / OpenReview crawlers, paper deep-dive, topic research, trend analysis, daily digest — out of the box. |
git clone https://github.com/LiRunGuo/Arhelper.git
cd Arhelper
pip install -e .Or use Docker:
docker compose upARH supports three ways to configure LLM settings (in order of priority):
Create ~/.arh/.env file (NOT the project directory):
mkdir -p ~/.arh
cp .env.example ~/.arh/.env
$EDITOR ~/.arh/.envFill in at least:
# Required: Your LLM API Key
ARH_LLM_API_KEY=sk-or-v1-... # OpenRouter key
# OR
ARH_LLM_API_KEY=sk-... # OpenAI / DeepSeek direct key
# Optional: Custom API endpoint (for OpenRouter, Azure, etc.)
ARH_LLM_BASE_URL=https://openrouter.ai/api/v1
# Optional: Model name (default: gpt-3.5-turbo)
ARH_LLM_MODEL=deepseek/deepseek-v4-flashYou can also export in shell (for current session only):
export ARH_LLM_API_KEY="sk-..."
export ARH_LLM_BASE_URL="https://openrouter.ai/api/v1"
export ARH_LLM_MODEL="deepseek/deepseek-v4-flash"Copy and edit the config template:
cp config.yaml.example ~/.arh/config.yaml
$EDITOR ~/.arh/config.yamlKey settings:
llm:
provider: "openai" # openai / anthropic / deepseek / ollama / openrouter
api_key: "${ARH_LLM_API_KEY}" # Reference env var or put key directly
base_url: "${ARH_LLM_BASE_URL}" # Custom endpoint (OpenRouter, etc.)
model: "deepseek/deepseek-v4-flash"
temperature: 0.7
max_tokens: 2048For development only: config.yaml or .env in project root (ARH will detect them, but NOT recommended for security).
# ~/.arh/.env
ARH_LLM_API_KEY=sk-or-v1-...
ARH_LLM_BASE_URL=https://openrouter.ai/api/v1
ARH_LLM_MODEL=deepseek/deepseek-v4-flashSearch models: /model search <keyword>
ARH_LLM_API_KEY=sk-...
ARH_LLM_BASE_URL=https://api.openai.com/v1
ARH_LLM_MODEL=gpt-4oARH_LLM_API_KEY=sk-...
ARH_LLM_BASE_URL=https://api.deepseek.com
ARH_LLM_MODEL=deepseek-chat# No API key needed
ARH_LLM_API_KEY=ollama
ARH_LLM_BASE_URL=http://localhost:11434/v1
ARH_LLM_MODEL=llama3ARH_LLM_API_KEY=sk-ant-...
ARH_LLM_BASE_URL=https://api.anthropic.com
ARH_LLM_MODEL=claude-3-5-sonnet-20241022Check installation status:
arh doctorarh # Interactive CLI (= arh chat)
arh chat # Same as above
arh config # View current configuration
arh config edit # Open config.yaml with $EDITOR
arh config set K=V # Change single config item
arh doctor # Environment / dependency / key self-check
arh skills list # List loaded skills
arh backup # Package ~/.arh as tar.gz
arh versionCan also run with python main.py for the same subcommands without installation.
Resume last session:
arh chat --resume <session_id>
# Or
ARH_RESUME_SESSION=<session_id> arh chatSwitch model (no restart needed):
/model openai/gpt-4o # Switch for current session
/model openai/gpt-4o --global # Persist to config.yaml
/model search attention # Search OpenRouter model catalog
Available after entering arh chat. Full list in arh/gateway/cli/completer.py.
| Group | Commands | Description |
|---|---|---|
| Session | /new /reset /history /save /title /branch /retry /undo |
Session lifecycle |
| Context | /compress /snapshot /usage /insights |
Manual compression, snapshot, token stats |
| Execution | /stop /background /queue /steer /btw |
Abort / background / queue / side-channel |
| Tools | /tools /skills /plugins /cron |
View available capabilities |
| Mode | /mode /yolo /verbose /allow-rules |
Permission mode & approval memory |
| Model | /model /llm /provider |
Runtime model switch (--global writes back to config) |
| Resume | /resume /checkpoints /tasks /agents |
Resume from checkpoint / active tasks |
| Other | /config /profile /env /debug /copy /reload /quit |
— |
ARH runs with maximum security posture by default:
- Plan / Execute Hard-binding: Agent can only use read-only tools by default. Write operations (file edits, command execution, crawling) must go through
task_manage(create)to create a plan, thenexit_plan_modefor approval. - ApprovalGate: Dangerous commands (
rm -rf,dd,mkfs,shutdown,DROP TABLE, etc. — 13 patterns) are automatically intercepted withy / a / nthree-way prompt. Pressato remember and skip future prompts for same command fingerprint. - PermissionMode 4 levels:
default(plan hard-binding) →plan(read-only) →acceptEdits(allow edits) →yolo(allow all, use with caution). - Gateway Authentication:
config.yamlgateway.security.auth_modesupportsnone/token/password. When set totokenorpassword, unauthenticated requests are rejected. - SSRF Protection:
web_fetchtool has built-in SSRF Guard that blocks requests to internal network addresses. - Filesystem Policy:
fs_policywhitelist / blacklist to restrict paths Agent can read/write. .envIsolation: Sensitive info (API keys) stored in.env, included in.gitignore, never committed.
Location: arh/skills/builtin/. Format: YAML frontmatter + Markdown body.
| Skill | Purpose |
|---|---|
arxiv |
Search, parse arXiv papers, output metadata + abstract + BibTeX |
paper_deep_dive |
Paper's problem background / method innovation / experiments / limitations & insights |
topic_research |
Complete research survey on a topic, structured report (theme / methods / datasets / gaps) |
trend_analysis |
Trend hotspots and evolution paths in a field |
daily_digest |
Today's curated digest from arXiv / HuggingFace / GitHub |
ocr_documents |
PDF / scanned document text extraction (pymupdf + marker-pdf) |
codebase_inspection |
Repository health (scale / language / TODO / dependencies) |
github_code_review |
Analyze git diff, provide bug / security / style / performance suggestions |
systematic_debugging |
4-stage root cause analysis, no code changes allowed without understanding root cause |
test_driven_development |
RED / GREEN / REFACTOR three-phase TDD |
writing_plans |
Executable plan generator for multi-step tasks |
Self-learning Skill: After successful complex tasks (5+ tool calls, no fatal errors), ARH automatically prompts whether to save as Skill. After confirmation, writes to arh/skills/learned/, auto-loaded on next startup, reusable via /skill or LLM tool call.
31 tools, directly callable by Agent. Security policies in arh/tools/registry.py.
| Category | Tools | Description |
|---|---|---|
| File | read_file write_file edit_file glob grep |
Read/write / search / replace |
| Execution | exec process |
Shell commands + subprocess management |
| Network | web_fetch web_search crawl |
Web scraping / search / crawlers (with SSRF protection) |
| Paper Search | search_paper search_openalex |
Multi-source paper search / OpenAlex precise search |
| Paper Analysis | analyze_paper find_citations find_references find_similar |
Paper analysis / citation chain / references / similar papers |
| Open Access | check_oa |
Unpaywall open access detection + PDF links |
| Citation Export | export_citation |
BibTeX / RIS / APA / MLA format export |
| Literature Review | literature_review |
Multi-source search + topic clustering + trend analysis |
| Daily Digest | get_daily_papers |
arXiv / HuggingFace / GitHub daily digest |
| Topic Suggestion | research_recommend |
Topic / direction suggestions |
| Agent | task_manage enter_plan_mode exit_plan_mode spawn_subagent run_skill resume_task |
Task / plan / sub-agent / skill scheduling |
See Configuration (Important) section above for detailed setup guide.
llm:
provider: "openai" # openai / anthropic / deepseek / ollama
api_key: "${ARH_LLM_API_KEY}" # Reference env var or put key directly
base_url: "${ARH_LLM_BASE_URL}" # Custom endpoint (OpenRouter, etc.)
model: "deepseek/deepseek-v4-flash"
temperature: 0.7
max_tokens: 2048
fallback:
enabled: true
fallback_models: [] # e.g. ["openai/gpt-4o", "ollama/llama3"]
crawler:
unpaywall_email: "" # Required, Unpaywall API needs it
crossref_email: "" # Recommended, enters Crossref polite pool
openalex_email: "" # Optional, enters OpenAlex polite pool
gateway:
security:
auth_mode: "none" # none / token / password| Variable | Purpose | Example |
|---|---|---|
ARH_LLM_API_KEY |
LLM API key (required) | sk-... |
ARH_LLM_BASE_URL |
Custom API endpoint | https://openrouter.ai/api/v1 |
ARH_LLM_MODEL |
Override default model | deepseek/deepseek-v4-flash |
ARH_DEBUG |
Debug mode | true |
ARH_GATEWAY_PORT |
Gateway port | 8900 |
ARH_GATEWAY_TOKEN |
Gateway auth token | my-secret-token |
ARH_RESUME_SESSION |
Resume specified session | 20260507-abc123 |
UNPAYWALL_EMAIL |
Unpaywall API email (required) | you@example.com |
CROSSREF_EMAIL |
Crossref API email (recommended) | you@example.com |
OPENALEX_EMAIL |
OpenAlex API email (optional) | you@example.com |
Environment variables can be referenced in
config.yamlas${ENV_VAR}.
arh/
├── cli_entry.py # CLI entry point (argparse subcommands)
├── core/ # App lifecycle / agent_loop / context_engine / logger / paths
├── runtime/ # AgentRuntime / approval / permission_mode / checkpoint / session_reflector / skill_extractor
├── tools/ # 31 LLM-callable tools + registry + ssrf_guard
├── data/ # SQLAlchemy ORM + SQLite database (auto-migration)
├── server/ # FastMCP server (SSE/stdio dual mode)
├── gateway/ # Hub-Spoke control plane (cli ✅ / telegram ✅ / feishu 🔧 / wechat 🔧 / api)
├── llm/ # providers / provider_registry / prompt_cache / openrouter_catalog
├── crawler/ # arxiv / huggingface / github / openreview
├── research/ # s2_client / openalex_client / crossref_client / unpaywall_client / pwc_client / search_orchestrator / keyword_translator
├── interaction/ # memory / memory_index / memory_recall / auto_memory / persona / nlu
├── skills/ # builtin (11) + learned skill loader
├── ui/ # console / theme / renderer (rich TUI)
└── plugins/ # Built-in plugins (help / daily_push)
tests/ # pytest cases (248 passed, 2 xfailed, covering approval/compression/session isolation/model switch/UI/CLI/academic tools/hallucination check)
docs/ # Sub-module docs (e.g. TELEGRAM_SETUP.md)
main.py # Compatibility entry (= arh.cli_entry)
pip install -e ".[dev]"
pytest # 248 passed, 2 xfailedCoverage: approval fingerprint, context compression, logging system, session_id isolation, model switching, UI rendering, CLI commands, academic toolchain, hallucination check.
See ARCHITECTURE.md for detailed architecture — layered diagram, module responsibilities, complete data flow of a single request, and extension points (adding tools / providers / channels / skills).
git clone https://github.com/LiRunGuo/Arhelper.git
cd Arhelper
pip install -e ".[dev]"
pytest # Confirm all tests passDevelopment guidelines:
- Code style:
ruff check --fix(line-length = 100, target = py39) - New tool: Create new module in
arh/tools/, inheritBaseTool, implementname/description/parameters/run().registry.auto_discover()will automatically find it. - New API Client: Create new module in
arh/research/, inheritBaseAPIClient(with rate limiting, retry, timeout), call as needed in corresponding tools. - New Skill: Write
.md(YAML frontmatter + body) inarh/skills/builtin/,SkillLoaderauto-loads it. - New LLM Provider: Inherit
BaseLLMProviderinarh/llm/providers/, implementchat/stream. - New Channel: Implement
init / start / stop / sendinarh/gateway/<channel>/.
ARH is an original implementation, written from scratch in Python. The
architectural patterns below were studied as design inspiration —
no source code was copied, vendored, or transcribed from these projects.
See NOTICE for the full attribution and per-project
inspiration scope.
| Project | License | Inspiration scope (ideas only) |
|---|---|---|
| Claude Code | proprietary | plan mode, ExitPlanMode, auto-compact, memory guide, allowedRules |
| hermes-agent | MIT | Session reflection, skill_manager, PermissionMode, OpenRouter catalog |
| OpenClaw | MIT | Hub-Spoke Gateway, AgentRuntime layering, ToolRegistry + Policy, security model |
| Nanobot | MIT | AgentRunner loop, Consolidator |
| OpenHarness | MIT | run_query while-loop, AutoCompactState, streaming timeout strategy |
| AstrBot | AGPL-3.0 |
SQLite WAL convention, multi-platform adapter naming (general patterns from public docs only — no code derived) |
AGPL note: AstrBot is licensed under AGPL-3.0, a strong copyleft license. ARH deliberately contains no AstrBot source code; only publicly-documented architectural conventions (e.g. enabling SQLite WAL mode) were referenced. Future contributions that would actually port AstrBot code MUST be rejected, otherwise the entire ARH project would have to relicense to AGPL-3.0.
MIT © 2025-2026 ARH Contributors
ARH itself is MIT-licensed. Third-party Python dependencies retain
their own licenses; see NOTICE for the full list.