
Arxiv Search
Search arXiv preprints with semantic full-text queries from the terminal or via an agent, backed by the Valyu API.
Overview
arxiv-search is an agent skill for the Idea phase that runs semantic full-text arXiv searches through the Valyu API from a Node/bash CLI.
Install
npx skills add https://github.com/yorkeccak/scientific-skills --skill arxiv-searchWhat is this skill?
- Node CLI (`search.mjs`) with bash wrapper for agent discoverability (`--path`, `--script-dir`)
- Full-text semantic search across arXiv preprints via Valyu API (`https://api.valyu.ai/v1`)
- API key from `VALYU_API_KEY` or persisted `~/.valyu/config.json`
- Helps agents locate the script path without guessing repo layout
- Valyu API base `https://api.valyu.ai/v1`
- Config path `~/.valyu/config.json`
Adoption & trust: 1k installs on skills.sh; 47 GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need credible papers fast while scoping a product or model approach, but manual arXiv browsing does not scale inside an agent loop.
Who is it for?
Solo builders doing technical due diligence, benchmarking ideas against recent preprints, or feeding an agent a repeatable literature query step.
Skip if: Paywalled journal access, citation management, or deep PDF extraction without a separate reading pipeline—this skill is search-only.
When should I use this skill?
You need full-text or semantic search across arXiv preprints from the terminal or within an agent research step.
What do I get? / Deliverables
You get structured search results from arXiv preprints via Valyu, with a reproducible CLI path agents can invoke using a stored or env-based API key.
- arXiv search result sets from Valyu API
- Resolved CLI script path for agent tooling
Recommended Skills
Journey fit
Literature discovery belongs at the start of the journey when you are validating technical approaches and surveying prior art. arxiv-search is a dedicated research integration—not build or ship tooling—so idea/research is the canonical shelf.
How it compares
Valyu-backed arXiv CLI for agents, not a general web search skill or Zotero workflow.
Common Questions / FAQ
Who is arxiv-search for?
Indie builders and agent users in scientific or ML-tinged products who want programmatic arXiv discovery from the scientific-skills bundle.
When should I use arxiv-search?
During idea research when exploring feasibility, when validating a novel feature against prior art, or when an agent needs `--path` to wire the search script into a larger analysis skill chain.
Is arxiv-search safe to install?
It uses network access and stores API keys locally when configured; review the Security Audits panel on this Prism page and treat `VALYU_API_KEY` like any third-party secret.
SKILL.md
READMESKILL.md - Arxiv Search
#!/bin/bash # arXiv Search CLI wrapper SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_PATH="${SCRIPT_DIR}/search" # Special commands for discoverability case "$1" in --path|--location|--where) echo "$SCRIPT_PATH" exit 0 ;; --script-dir) echo "$SCRIPT_DIR" exit 0 ;; esac node "${SCRIPT_DIR}/search.mjs" "$@" #!/usr/bin/env node /** * arXiv Search via Valyu API * Full-text search across arXiv preprints with semantic search capabilities */ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; import { homedir } from 'os'; import { join } from 'path'; const VALYU_API_BASE = 'https://api.valyu.ai/v1'; const CONFIG_DIR = join(homedir(), '.valyu'); const CONFIG_FILE = join(CONFIG_DIR, 'config.json'); /** * Get API key from multiple sources (in order of priority): * 1. Environment variable (VALYU_API_KEY) * 2. Config file (~/.valyu/config.json) */ function getApiKey() { if (process.env.VALYU_API_KEY) { return process.env.VALYU_API_KEY; } if (existsSync(CONFIG_FILE)) { try { const config = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8')); if (config.apiKey) { return config.apiKey; } } catch (e) { // Ignore parse errors } } return null; } /** * Save API key to config file */ function saveApiKey(apiKey) { if (!existsSync(CONFIG_DIR)) { mkdirSync(CONFIG_DIR, { recursive: true }); } let config = {}; if (existsSync(CONFIG_FILE)) { try { config = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8')); } catch (e) { // Start fresh if parse fails } } config.apiKey = apiKey; writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2)); return true; } /** * Return setup required response */ function setupRequiredResponse() { return { success: false, setup_required: true, message: "Valyu API key not configured. Get your free API key ($10 credits) at https://platform.valyu.ai" }; } /** * Search arXiv via Valyu API */ async function searchArxiv(query, maxResults = 10) { const apiKey = getApiKey(); if (!apiKey) { return setupRequiredResponse(); } try { const response = await fetch(`${VALYU_API_BASE}/search`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey }, body: JSON.stringify({ query: query, search_type: 'proprietary', included_sources: ['valyu/valyu-arxiv'], limit: maxResults }) }); const data = await response.json(); if (!response.ok) { return { success: false, error: data.detail || data.message || `HTTP ${response.status}`, status: response.status }; } return { success: true, type: 'arxiv_search', query: query, result_count: data.results?.length || 0, results: data.results || [], cost: data.cost || 0 }; } catch (error) { return { success: false, error: error.message }; } } /** * Setup command - save API key */ function setup(apiKey) { if (!apiKey) { return { success: false, error: "API key required. Usage: search setup <api-key>" }; } saveApiKey(apiKey); return { success: true, type: 'setup', message: "API key saved to ~/.valyu/config.json" }; } // Main CLI handler const [,, command, ...args] = process.argv; (async () => { let result; if (command === 'setup') { result = setup(args[0]); } else { // Treat first arg as query, second as maxResults const query = command || ''; const maxResults = args[0] ? parseInt(args[0], 10) : 10; if (!query) { result = { success: false, error: "Query required. Usage: search <query> [maxResults]" }; } else { result = await searchArxiv(query, maxResults); } } console.log(JSON.stringify(result, null, 2)); process.e