@anysiteio/agent-skills 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +13 -1
- package/bin/install.js +174 -45
- package/package.json +1 -1
- package/skills/anysite-cli/SKILL.md +434 -178
- package/skills/anysite-cli/references/api-reference.md +73 -8
- package/skills/anysite-cli/references/dataset-guide.md +455 -19
- package/skills/anysite-cli/references/llm-reference.md +274 -0
- package/skills/anysite-mcp-migration/SKILL.md +279 -0
|
@@ -1,292 +1,548 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: anysite-cli
|
|
3
|
-
description: Operate the anysite command-line tool for web data extraction, batch API processing, multi-source dataset pipelines with scheduling/transforms/exports, and
|
|
3
|
+
description: Operate the anysite command-line tool for web data extraction, batch API processing, multi-source dataset pipelines with scheduling/transforms/exports, database operations, and LLM-powered data analysis. Use when users ask to collect data from LinkedIn, Instagram, Twitter, or any web source via CLI; create or run dataset pipelines; schedule automated collection; batch-process API calls; query collected data with SQL; load data into PostgreSQL or SQLite; analyze data with LLM (summarize, classify, enrich, match, deduplicate); or work with anysite commands. Triggers on anysite CLI usage, data collection, dataset creation, scraping, API batch calls, scheduling, database loading, or LLM analysis tasks.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Anysite CLI
|
|
7
7
|
|
|
8
|
-
Command-line tool for web data extraction, dataset pipelines, and database operations.
|
|
8
|
+
Command-line tool for web data extraction, dataset pipelines, and database operations.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Agent Planning Workflow
|
|
11
|
+
|
|
12
|
+
**BEFORE planning any data collection task, follow this sequence:**
|
|
13
|
+
|
|
14
|
+
1. **Discover available endpoints**
|
|
15
|
+
```bash
|
|
16
|
+
anysite describe --search "<keyword>" # Search by domain (linkedin, company, user, etc.)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. **Select endpoints needed for the task** — identify which endpoints will provide the required data
|
|
20
|
+
|
|
21
|
+
3. **Inspect each selected endpoint**
|
|
22
|
+
```bash
|
|
23
|
+
anysite describe /api/linkedin/company # View input params and output fields
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
4. **Only then plan** — now you know the exact parameters, field names, and data structure to build your config or API calls
|
|
27
|
+
|
|
28
|
+
This prevents errors from wrong endpoint paths, missing required parameters, or incorrect field names in dependencies.
|
|
29
|
+
|
|
30
|
+
## Best Practices
|
|
31
|
+
|
|
32
|
+
1. **Use dataset pipelines for multi-step tasks**
|
|
33
|
+
- If a task requires sequential API calls, LLM enrichment, or chained data processing — create a `dataset.yaml` config instead of running multiple ad-hoc commands
|
|
34
|
+
- Dataset pipelines handle dependencies, incremental collection, and error recovery automatically
|
|
35
|
+
- Even for "simple" tasks that grow in scope, a dataset config is easier to maintain
|
|
36
|
+
- Benefits: run history, incremental sync, scheduling, notifications, DB loading
|
|
37
|
+
|
|
38
|
+
2. **Save data in Parquet format by default** — unless user requests another format or CSV/JSON fits better
|
|
39
|
+
|
|
40
|
+
3. **Prefer datasets over ad-hoc scripts** — one dataset.yaml replaces dozens of shell commands
|
|
41
|
+
|
|
42
|
+
## Quick Start Checklist
|
|
43
|
+
|
|
44
|
+
Before any data collection task:
|
|
11
45
|
|
|
12
46
|
```bash
|
|
13
|
-
#
|
|
47
|
+
# 1. Check CLI is available and see latest changes
|
|
14
48
|
anysite --version
|
|
49
|
+
anysite changelog --last 1 --json # Check what's new in this version
|
|
50
|
+
# If not found: source .venv/bin/activate or pip install anysite-cli
|
|
15
51
|
|
|
16
|
-
#
|
|
17
|
-
anysite config set api_key sk-xxxxx
|
|
18
|
-
|
|
19
|
-
# Update schema cache (required for endpoint discovery and type inference)
|
|
52
|
+
# 2. Update schema cache (required for endpoint discovery)
|
|
20
53
|
anysite schema update
|
|
54
|
+
|
|
55
|
+
# 3. Verify API key
|
|
56
|
+
anysite config get api_key
|
|
57
|
+
# If not set: anysite config set api_key sk-xxxxx
|
|
21
58
|
```
|
|
22
59
|
|
|
23
|
-
|
|
60
|
+
After upgrading, run `anysite changelog --since <old_version> --json` to discover new features.
|
|
61
|
+
|
|
62
|
+
## Endpoint Discovery
|
|
63
|
+
|
|
64
|
+
**ALWAYS discover endpoints before writing API calls or dataset configs:**
|
|
24
65
|
|
|
25
66
|
```bash
|
|
26
|
-
#
|
|
27
|
-
anysite
|
|
67
|
+
anysite describe # List all endpoints
|
|
68
|
+
anysite describe --search "company" # Search with dependency context
|
|
69
|
+
anysite describe /api/linkedin/company # Full details: params, output, connections
|
|
28
70
|
|
|
29
|
-
|
|
30
|
-
anysite api /api/linkedin/company company=anthropic --format table
|
|
31
|
-
anysite api /api/linkedin/search/users title=CTO count=50 --format csv --output ctos.csv
|
|
71
|
+
```
|
|
32
72
|
|
|
33
|
-
|
|
34
|
-
anysite api /api/linkedin/user user=satyanadella --fields "name,headline,follower_count"
|
|
35
|
-
anysite api /api/linkedin/user user=satyanadella --exclude "certifications,patents"
|
|
73
|
+
Search returns matched endpoints plus upstream providers (who can supply input IDs) and downstream consumers (who can use output IDs). Use this to plan endpoint chains for dataset pipelines.
|
|
36
74
|
|
|
37
|
-
|
|
38
|
-
anysite api /api/linkedin/user user=satyanadella -q | jq '.follower_count'
|
|
75
|
+
Input params show type, description, examples, and defaults. Array params show item structure:
|
|
39
76
|
```
|
|
77
|
+
Input parameters:
|
|
78
|
+
* urn string User URN, only fsd_profile urn type is allowed
|
|
79
|
+
example: "urn:li:fsd_profile:ACoAABXy1234"
|
|
80
|
+
count integer Number of posts to return
|
|
81
|
+
default: 20
|
|
82
|
+
companies array[object{type,value}] Company URNs
|
|
83
|
+
example: [{"type": "company", "value": "14064608"}]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Prerequisites
|
|
40
87
|
|
|
41
|
-
**Discover endpoints first:**
|
|
42
88
|
```bash
|
|
43
|
-
anysite
|
|
44
|
-
|
|
45
|
-
|
|
89
|
+
pip install "anysite-cli[data]" # DuckDB + PyArrow for dataset commands
|
|
90
|
+
pip install "anysite-cli[llm]" # LLM analysis (openai/anthropic)
|
|
91
|
+
pip install "anysite-cli[postgres]" # PostgreSQL adapter
|
|
92
|
+
pip install "anysite-cli[clickhouse]" # ClickHouse adapter
|
|
93
|
+
|
|
94
|
+
anysite config set api_key sk-xxxxx # Configure API key
|
|
95
|
+
anysite schema update # Update schema cache
|
|
96
|
+
anysite llm setup # Interactive setup (human)
|
|
97
|
+
anysite llm setup --provider openai --api-key sk-xxx --no-test # Non-interactive (agent)
|
|
98
|
+
anysite llm setup --provider anthropic --api-key-env ANTHROPIC_API_KEY --no-test
|
|
99
|
+
anysite db add pg --type postgres --host localhost --database mydb --user app --password secret
|
|
100
|
+
# Or via env var: anysite db add pg ... --password-env PGPASS
|
|
101
|
+
anysite db add ch --type clickhouse --host ch.example.com --port 8443 --database analytics --user app --password secret --ssl
|
|
46
102
|
```
|
|
47
103
|
|
|
48
|
-
|
|
104
|
+
## Authentication
|
|
49
105
|
|
|
50
|
-
|
|
106
|
+
```bash
|
|
107
|
+
anysite auth login # Interactive browser-based OAuth2 (human)
|
|
108
|
+
anysite auth login --force --no-browser # Re-authenticate without confirmation (agent)
|
|
109
|
+
anysite auth status # Check current auth status
|
|
110
|
+
anysite auth status --json # Machine-readable auth status
|
|
111
|
+
anysite auth logout # Interactive logout (human)
|
|
112
|
+
anysite auth logout --force # Logout without confirmation (agent)
|
|
113
|
+
```
|
|
51
114
|
|
|
52
|
-
|
|
115
|
+
## Single API Call
|
|
53
116
|
|
|
54
117
|
```bash
|
|
55
|
-
|
|
56
|
-
anysite api /api/linkedin/
|
|
118
|
+
anysite api /api/linkedin/user user=satyanadella
|
|
119
|
+
anysite api /api/linkedin/company company=anthropic --format table
|
|
120
|
+
anysite api /api/linkedin/search/users keywords="CTO" count=50 --format csv --output ctos.csv
|
|
121
|
+
anysite api /api/linkedin/user user=satyanadella --fields "name,headline,urn.value" -q | jq
|
|
122
|
+
```
|
|
57
123
|
|
|
58
|
-
|
|
59
|
-
anysite api /api/linkedin/user --from-file users.jsonl --parallel 3 --on-error skip
|
|
124
|
+
### URN/Name Parameter Formats
|
|
60
125
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
126
|
+
Parameters like `location`, `current_companies`, `industry` accept two formats:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Single name (text search) — resolves to URNs automatically
|
|
130
|
+
location="London"
|
|
131
|
+
current_companies="Microsoft"
|
|
64
132
|
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
|
|
133
|
+
# Multiple URNs (direct) — use JSON array in single quotes
|
|
134
|
+
'location=["urn:li:geo:101165590", "urn:li:geo:101282230"]'
|
|
135
|
+
'current_companies=["urn:li:company:1035", "urn:li:company:1441"]'
|
|
68
136
|
```
|
|
69
137
|
|
|
70
|
-
**
|
|
138
|
+
**Note:** List of names `["Microsoft", "Google"]` is NOT supported — use either one name OR multiple URNs.
|
|
71
139
|
|
|
72
|
-
##
|
|
140
|
+
## Batch Processing
|
|
73
141
|
|
|
74
|
-
|
|
142
|
+
```bash
|
|
143
|
+
anysite api /api/linkedin/user --from-file users.txt --input-key user \
|
|
144
|
+
--parallel 5 --rate-limit "10/s" --on-error skip --progress --stats
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Dataset Pipeline (Multi-Source Collection)
|
|
148
|
+
|
|
149
|
+
For complex data collection with dependencies, LLM enrichment, scheduling — use dataset pipelines.
|
|
150
|
+
|
|
151
|
+
### Initialize
|
|
75
152
|
|
|
76
|
-
### Step 1: Initialize
|
|
77
153
|
```bash
|
|
78
154
|
anysite dataset init my-dataset
|
|
79
155
|
# Creates my-dataset/dataset.yaml with template config
|
|
80
156
|
```
|
|
81
157
|
|
|
82
|
-
###
|
|
83
|
-
|
|
84
|
-
Three source types:
|
|
85
|
-
- **Independent** — single API call with static `params`
|
|
86
|
-
- **from_file** — batch calls iterating over input file values
|
|
87
|
-
- **Dependent** — batch calls using values extracted from a parent source
|
|
158
|
+
### Six Source Types
|
|
88
159
|
|
|
89
|
-
|
|
160
|
+
1. **Independent** — single API call with static `input`
|
|
161
|
+
2. **from_file** — batch calls iterating over input file values
|
|
162
|
+
3. **Dependent** — batch calls using values extracted from a parent source
|
|
163
|
+
4. **Union (type: union)** — combine records from multiple parent sources into one
|
|
164
|
+
5. **LLM (type: llm)** — process parent data through LLM without API calls
|
|
165
|
+
6. **SQL (type: sql)** — query a database connection or dataset Parquet files via DuckDB
|
|
90
166
|
|
|
91
|
-
|
|
167
|
+
### Comprehensive Dataset YAML Reference
|
|
92
168
|
|
|
93
169
|
```yaml
|
|
94
|
-
name: my-dataset
|
|
170
|
+
name: my-dataset # Dataset name (required)
|
|
171
|
+
description: Optional description # Human-readable description
|
|
172
|
+
|
|
95
173
|
sources:
|
|
174
|
+
# === TYPE 1: Independent source (single API call) ===
|
|
175
|
+
- id: search_results # Unique identifier (required)
|
|
176
|
+
endpoint: /api/linkedin/search/users # API endpoint (required for type: api)
|
|
177
|
+
input: # Static API parameters
|
|
178
|
+
keywords: "software engineer"
|
|
179
|
+
count: 50
|
|
180
|
+
parallel: 1 # Concurrent requests: 1-10 (default: 1)
|
|
181
|
+
rate_limit: "10/s" # Rate limit: "N/s", "N/m", "N/h"
|
|
182
|
+
on_error: stop # Error handling: stop | skip (default: stop)
|
|
183
|
+
|
|
184
|
+
- id: search_extra # Another search (can be combined with union)
|
|
185
|
+
endpoint: /api/linkedin/search/users
|
|
186
|
+
input: { keywords: "data engineer", count: 50 }
|
|
187
|
+
|
|
188
|
+
# === TYPE 2: from_file source (batch from file) ===
|
|
96
189
|
- id: companies
|
|
97
190
|
endpoint: /api/linkedin/company
|
|
98
|
-
from_file: companies.txt
|
|
99
|
-
|
|
191
|
+
from_file: companies.txt # Input file: .txt (line per value), .csv, .jsonl
|
|
192
|
+
file_field: company_slug # CSV column name (for CSV files only)
|
|
193
|
+
input_key: company # API parameter to fill with each value
|
|
100
194
|
parallel: 3
|
|
101
|
-
transform: # Applied to exports only (Parquet keeps all fields)
|
|
102
|
-
filter: '.employee_count > 10'
|
|
103
|
-
fields: [name, url, employee_count]
|
|
104
|
-
add_columns:
|
|
105
|
-
batch: "q1-2026"
|
|
106
|
-
export: # Export after Parquet write
|
|
107
|
-
- type: file
|
|
108
|
-
path: ./output/companies-{{date}}.csv
|
|
109
|
-
format: csv
|
|
110
|
-
db_load:
|
|
111
|
-
fields: [name, url, employee_count]
|
|
112
195
|
|
|
196
|
+
# === TYPE 3: Dependent source (values from parent) ===
|
|
113
197
|
- id: employees
|
|
114
198
|
endpoint: /api/linkedin/company/employees
|
|
115
199
|
dependency:
|
|
116
|
-
from_source: companies
|
|
117
|
-
field: urn.value
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
200
|
+
from_source: companies # Parent source ID (required)
|
|
201
|
+
field: urn.value # Dot-notation path to extract from parent records
|
|
202
|
+
match_by: name # Alternative: fuzzy match instead of exact field
|
|
203
|
+
dedupe: true # Remove duplicate values (default: false)
|
|
204
|
+
input_key: companies # API parameter for extracted values
|
|
205
|
+
input_template: # Transform values before API call
|
|
121
206
|
companies:
|
|
122
207
|
- type: company
|
|
123
|
-
value: "{value}"
|
|
208
|
+
value: "{value}" # {value} = extracted value placeholder
|
|
124
209
|
count: 5
|
|
125
|
-
|
|
126
|
-
|
|
210
|
+
refresh: auto # Incremental behavior: auto (default) | always | never
|
|
211
|
+
# never = skip if data exists
|
|
212
|
+
|
|
213
|
+
# === Shorthand for dependent sources ===
|
|
214
|
+
# ${source.field} auto-expands to dependency + input_key:
|
|
215
|
+
- id: profiles
|
|
216
|
+
endpoint: /api/linkedin/user
|
|
217
|
+
input:
|
|
218
|
+
user: ${companies.urn.value} # Equivalent to dependency + input_key above
|
|
219
|
+
|
|
220
|
+
# === TYPE 4: Union source (combine multiple sources) ===
|
|
221
|
+
- id: all_search_results
|
|
222
|
+
type: union # Source type: api (default) | union | llm | sql
|
|
223
|
+
sources: [search_results, search_extra] # Parent source IDs to combine (required)
|
|
224
|
+
dedupe_by: urn.value # Optional: field path for deduplication (dot-notation)
|
|
225
|
+
# NOTE: type: union cannot have endpoint, dependency, from_file, input_key, input
|
|
226
|
+
# NOTE: all sources in the list must have the same endpoint (same data structure)
|
|
227
|
+
# Records are annotated with _union_source = parent source ID
|
|
228
|
+
|
|
229
|
+
# === TYPE 5: LLM source (process parent data without API) ===
|
|
230
|
+
- id: employees_analyzed
|
|
231
|
+
type: llm # Source type: api (default) | union | llm | sql
|
|
232
|
+
dependency:
|
|
233
|
+
from_source: employees
|
|
234
|
+
field: name # Required by schema (not used for LLM sources)
|
|
235
|
+
llm: # LLM enrichment steps (required for type: llm)
|
|
236
|
+
- type: classify # Step types: classify | enrich | summarize | generate
|
|
237
|
+
categories: "developer,recruiter,executive" # Comma-separated (omit for auto-detect)
|
|
238
|
+
output_column: role_type # Output column name (default: category)
|
|
239
|
+
fields: [headline] # Record fields to include in LLM prompt
|
|
240
|
+
- type: enrich
|
|
241
|
+
add: # Field specs (required for enrich)
|
|
242
|
+
- "sentiment:positive/negative/neutral" # Enum: value1/value2/value3
|
|
243
|
+
- "language:string" # Types: string | number | integer | boolean
|
|
244
|
+
- "quality_score:1-10" # Range: min-max
|
|
245
|
+
fields: [headline, summary]
|
|
246
|
+
temperature: 0.0 # LLM temperature: 0.0-1.0 (default: 0.0)
|
|
247
|
+
provider: openai # Provider override: openai | anthropic
|
|
248
|
+
model: gpt-4o-mini # Model override
|
|
249
|
+
- type: summarize
|
|
250
|
+
max_length: 50 # Max words (default: 100)
|
|
251
|
+
output_column: bio
|
|
252
|
+
- type: generate
|
|
253
|
+
prompt: "Write pitch for {name}" # Template with {field} placeholders (required)
|
|
254
|
+
output_column: pitch
|
|
255
|
+
temperature: 0.7 # Higher for creative text
|
|
256
|
+
export: # Export destinations (runs after Parquet write)
|
|
257
|
+
- type: file
|
|
258
|
+
path: ./output/{{source}}-{{date}}.csv # Templates: {{date}}, {{source}}, {{dataset}}
|
|
259
|
+
format: csv # Format: json | jsonl | csv
|
|
260
|
+
# NOTE: type: llm cannot have endpoint, from_file, input_key, input
|
|
261
|
+
|
|
262
|
+
# === TYPE 6: SQL source (query a database) ===
|
|
263
|
+
# Mode A: Named connection (query external database)
|
|
264
|
+
- id: billing_users
|
|
265
|
+
type: sql
|
|
266
|
+
connection: billing # Named connection from 'anysite db add'
|
|
267
|
+
query: "SELECT name, email FROM subscriptions WHERE status = 'inactive'"
|
|
268
|
+
# query_file: queries/inactive.sql # Alternative: read SQL from file
|
|
269
|
+
filter: ".email != null" # All base fields work: filter, llm, transform, export, db_load
|
|
270
|
+
|
|
271
|
+
# Mode B: Dataset views (no connection — query Parquet via DuckDB)
|
|
272
|
+
# Each collected source becomes a view by its id (hyphens → underscores)
|
|
273
|
+
- id: enriched_profiles
|
|
274
|
+
type: sql
|
|
275
|
+
query: |
|
|
276
|
+
SELECT u.*, c.description as company_desc
|
|
277
|
+
FROM user_profiles u
|
|
278
|
+
LEFT JOIN company_profiles c ON u._input_value = c._input_value
|
|
279
|
+
# Use for cross-source JOINs within the pipeline — no external DB needed
|
|
280
|
+
# NOTE: type: sql cannot have endpoint, from_file, input_key, input, parallel, rate_limit, on_error
|
|
281
|
+
|
|
282
|
+
# === OPTIONAL BLOCKS (any source type) ===
|
|
283
|
+
# THREE-LEVEL FILTERING:
|
|
284
|
+
# Level 1: source.filter — before LLM + Parquet (saves tokens, drops records entirely)
|
|
285
|
+
# Level 2: transform.filter — before exports only (Parquet keeps all records)
|
|
286
|
+
# Level 3: db_load.filter — before DB loading (Parquet keeps all records)
|
|
287
|
+
# All use same syntax: .field op value, booleans (true/false), and/or
|
|
288
|
+
- id: profiles
|
|
289
|
+
endpoint: /api/linkedin/user
|
|
290
|
+
dependency: { from_source: employees, field: internal_id.value }
|
|
291
|
+
input_key: user
|
|
292
|
+
filter: '.follower_count > 100' # Level 1: early filter (before LLM + Parquet)
|
|
293
|
+
transform: # Level 2: export filter (Parquet keeps all)
|
|
294
|
+
filter: '.location != ""' # Safe expression
|
|
295
|
+
fields: # Field selection with dot-notation aliases
|
|
296
|
+
- name
|
|
297
|
+
- urn.value AS urn_id
|
|
298
|
+
- headline
|
|
299
|
+
add_columns: # Static columns to inject
|
|
300
|
+
batch: "q1-2026"
|
|
301
|
+
export:
|
|
302
|
+
- type: file
|
|
303
|
+
path: ./output/profiles.csv
|
|
304
|
+
format: csv
|
|
305
|
+
- type: webhook
|
|
306
|
+
url: https://example.com/hook
|
|
307
|
+
headers: { X-Token: abc }
|
|
308
|
+
db_load: # Database loading config
|
|
309
|
+
filter: '.active == true' # Level 3: DB filter (only active to DB)
|
|
310
|
+
table: people # Custom table name (default: source ID)
|
|
311
|
+
key: urn.value # Unique key for diff-based incremental sync
|
|
312
|
+
sync: full # Sync mode: full (default) | append (no DELETE)
|
|
313
|
+
fields: # Fields to load (default: all except _input_value)
|
|
314
|
+
- name
|
|
315
|
+
- urn.value AS urn_id
|
|
316
|
+
- headline
|
|
317
|
+
exclude: [_input_value, raw_html] # Fields to skip
|
|
127
318
|
|
|
128
319
|
storage:
|
|
129
|
-
format: parquet
|
|
130
|
-
path: ./data/
|
|
320
|
+
format: parquet # Storage format (only parquet supported)
|
|
321
|
+
path: ./data/ # Storage directory (relative to dataset.yaml)
|
|
131
322
|
|
|
132
323
|
schedule:
|
|
133
|
-
cron: "0 9 * * *"
|
|
324
|
+
cron: "0 9 * * *" # Cron expression for scheduling
|
|
134
325
|
|
|
135
326
|
notifications:
|
|
136
327
|
on_complete:
|
|
137
328
|
- url: "https://hooks.slack.com/xxx"
|
|
329
|
+
headers: { Authorization: "Bearer token" }
|
|
138
330
|
on_failure:
|
|
139
331
|
- url: "https://alerts.example.com/fail"
|
|
140
332
|
```
|
|
141
333
|
|
|
142
|
-
###
|
|
143
|
-
```bash
|
|
144
|
-
# Preview plan
|
|
145
|
-
anysite dataset collect dataset.yaml --dry-run
|
|
334
|
+
### type: union Source Details
|
|
146
335
|
|
|
147
|
-
|
|
148
|
-
|
|
336
|
+
The `type: union` source combines records from multiple parent sources:
|
|
337
|
+
|
|
338
|
+
- **Requires**: non-empty `sources` list (parent source IDs)
|
|
339
|
+
- **Optional**: `dedupe_by` field path for removing duplicates (supports dot-notation)
|
|
340
|
+
- **Cannot have**: `endpoint`, `dependency`, `from_file`, `input_key`, `input`
|
|
341
|
+
- **Validation**: all parent sources must have the same endpoint (same data structure)
|
|
342
|
+
- **Use case**: merge multiple search results before a single dependent source processes them
|
|
149
343
|
|
|
150
|
-
|
|
151
|
-
|
|
344
|
+
```yaml
|
|
345
|
+
sources:
|
|
346
|
+
- id: search_cto
|
|
347
|
+
endpoint: /api/linkedin/search/users
|
|
348
|
+
input: { keywords: "CTO fintech", count: 50 }
|
|
152
349
|
|
|
153
|
-
|
|
154
|
-
|
|
350
|
+
- id: search_vp
|
|
351
|
+
endpoint: /api/linkedin/search/users
|
|
352
|
+
input: { keywords: "VP Engineering", count: 50 }
|
|
155
353
|
|
|
156
|
-
#
|
|
157
|
-
|
|
354
|
+
# Union combines all search results
|
|
355
|
+
- id: all_candidates
|
|
356
|
+
type: union
|
|
357
|
+
sources: [search_cto, search_vp]
|
|
358
|
+
dedupe_by: urn.value # Remove duplicates by URN
|
|
359
|
+
|
|
360
|
+
# Single dependent source processes all candidates
|
|
361
|
+
- id: profiles
|
|
362
|
+
endpoint: /api/linkedin/user
|
|
363
|
+
dependency:
|
|
364
|
+
from_source: all_candidates
|
|
365
|
+
field: urn.value
|
|
366
|
+
input_key: user
|
|
158
367
|
```
|
|
159
368
|
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
# SQL query
|
|
163
|
-
anysite dataset query dataset.yaml --sql "SELECT * FROM companies LIMIT 10"
|
|
369
|
+
Records from union sources are annotated with `_union_source` (the parent source ID they came from).
|
|
164
370
|
|
|
165
|
-
|
|
166
|
-
anysite dataset query dataset.yaml --source profiles \
|
|
167
|
-
--fields "name, urn.value AS urn_id, headline"
|
|
371
|
+
### type: llm Source Details
|
|
168
372
|
|
|
169
|
-
|
|
170
|
-
anysite dataset query dataset.yaml --interactive
|
|
373
|
+
The `type: llm` source processes existing parent data without making API calls:
|
|
171
374
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
```
|
|
375
|
+
- **Requires**: `dependency` (parent source) and non-empty `llm` list
|
|
376
|
+
- **Cannot have**: `endpoint`, `from_file`, `input_key`, `input`
|
|
377
|
+
- **Use case**: Run LLM enrichment on already-collected data, re-analyze with different prompts
|
|
176
378
|
|
|
177
|
-
### Step 5: Load into Database
|
|
178
379
|
```bash
|
|
179
|
-
#
|
|
180
|
-
anysite dataset
|
|
380
|
+
# Collect only the LLM source (reads parent Parquet, applies LLM steps)
|
|
381
|
+
anysite dataset collect dataset.yaml --source employees_analyzed
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Validate & Collect Commands
|
|
181
385
|
|
|
182
|
-
|
|
183
|
-
anysite dataset
|
|
386
|
+
```bash
|
|
387
|
+
anysite dataset validate dataset.yaml # Validate config (catches errors early)
|
|
388
|
+
anysite dataset collect dataset.yaml --dry-run # Preview plan
|
|
389
|
+
anysite dataset collect dataset.yaml # Run collection
|
|
390
|
+
anysite dataset collect dataset.yaml --load-db pg # Collect + auto-load to DB
|
|
391
|
+
anysite dataset collect dataset.yaml --incremental # Skip already-collected inputs
|
|
392
|
+
anysite dataset collect dataset.yaml --source employees # Single source + dependencies
|
|
393
|
+
anysite dataset collect dataset.yaml --no-llm # Skip LLM enrichment steps
|
|
394
|
+
anysite dataset collect dataset.yaml --limit 100 # Pilot run: max 100 inputs per source
|
|
184
395
|
```
|
|
185
396
|
|
|
186
|
-
|
|
397
|
+
### Incremental Collection (Resume Where You Left Off)
|
|
398
|
+
|
|
399
|
+
For `from_file` and `dependency` sources, anysite tracks collected input values in `metadata.json`. This enables resuming collection without re-fetching existing data.
|
|
400
|
+
|
|
401
|
+
**Workflow:**
|
|
402
|
+
```bash
|
|
403
|
+
# First run — collects all inputs
|
|
404
|
+
anysite dataset collect dataset.yaml
|
|
405
|
+
|
|
406
|
+
# Later: add new items to input file, run with --incremental
|
|
407
|
+
anysite dataset collect dataset.yaml --incremental
|
|
408
|
+
# → Only new items are collected, existing ones skipped
|
|
187
409
|
|
|
188
|
-
|
|
410
|
+
# Force full re-collection
|
|
411
|
+
anysite dataset reset-cursor dataset.yaml
|
|
412
|
+
anysite dataset collect dataset.yaml
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Per-source `refresh` option:**
|
|
189
416
|
```yaml
|
|
417
|
+
sources:
|
|
190
418
|
- id: profiles
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
- urn.value AS urn_id # Dot-notation extraction
|
|
197
|
-
- headline
|
|
198
|
-
- experience
|
|
199
|
-
exclude: [_input_value] # Fields to skip
|
|
200
|
-
```
|
|
419
|
+
refresh: auto # (default) respects --incremental
|
|
420
|
+
|
|
421
|
+
- id: posts
|
|
422
|
+
refresh: always # always re-collects, ignores --incremental
|
|
423
|
+
# use for time-sensitive data (feeds, activity)
|
|
201
424
|
|
|
202
|
-
|
|
425
|
+
- id: companies
|
|
426
|
+
refresh: never # skip if data exists (any snapshot)
|
|
427
|
+
```
|
|
203
428
|
|
|
429
|
+
**Reset cursor:**
|
|
204
430
|
```bash
|
|
205
|
-
#
|
|
206
|
-
anysite
|
|
431
|
+
anysite dataset reset-cursor dataset.yaml # all sources
|
|
432
|
+
anysite dataset reset-cursor dataset.yaml --source posts # specific source
|
|
433
|
+
```
|
|
207
434
|
|
|
208
|
-
|
|
209
|
-
anysite db test pg
|
|
210
|
-
anysite db list
|
|
211
|
-
anysite db schema pg --table users
|
|
435
|
+
### Query with DuckDB
|
|
212
436
|
|
|
213
|
-
|
|
214
|
-
|
|
437
|
+
```bash
|
|
438
|
+
anysite dataset query dataset.yaml --sql "SELECT * FROM companies LIMIT 10"
|
|
439
|
+
anysite dataset query dataset.yaml --source profiles --fields "name, urn.value AS id"
|
|
440
|
+
anysite dataset query dataset.yaml --source profiles --exclude "_input_value,_parent_source"
|
|
441
|
+
anysite dataset query dataset.yaml --interactive # SQL shell
|
|
442
|
+
anysite dataset stats dataset.yaml --source companies
|
|
443
|
+
anysite dataset profile dataset.yaml
|
|
444
|
+
```
|
|
215
445
|
|
|
216
|
-
|
|
217
|
-
cat updates.jsonl | anysite db upsert pg --table users --conflict-columns id --stdin
|
|
446
|
+
### Load into Database
|
|
218
447
|
|
|
219
|
-
|
|
220
|
-
anysite db
|
|
448
|
+
```bash
|
|
449
|
+
anysite dataset load-db dataset.yaml -c pg --drop-existing # Full load
|
|
450
|
+
anysite dataset load-db dataset.yaml -c pg # Incremental sync (when db_load.key set)
|
|
451
|
+
anysite dataset load-db dataset.yaml -c pg --snapshot 2026-01-15
|
|
452
|
+
```
|
|
221
453
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
454
|
+
### Compare Snapshots
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
anysite dataset diff dataset.yaml --source profiles --key urn.value
|
|
458
|
+
anysite dataset diff dataset.yaml --source profiles --key urn.value --from 2026-01-30 --to 2026-02-01
|
|
225
459
|
```
|
|
226
460
|
|
|
227
|
-
###
|
|
461
|
+
### Scheduling & History
|
|
462
|
+
|
|
228
463
|
```bash
|
|
229
|
-
#
|
|
464
|
+
anysite dataset schedule dataset.yaml --incremental --load-db pg # Generate cron entry
|
|
230
465
|
anysite dataset history my-dataset
|
|
231
|
-
|
|
232
|
-
# View logs for a specific run
|
|
233
466
|
anysite dataset logs my-dataset --run 42
|
|
467
|
+
anysite dataset reset-cursor dataset.yaml # Clear incremental state
|
|
468
|
+
```
|
|
234
469
|
|
|
235
|
-
|
|
236
|
-
anysite dataset schedule dataset.yaml --incremental --load-db pg
|
|
470
|
+
## Database Operations
|
|
237
471
|
|
|
238
|
-
|
|
239
|
-
|
|
472
|
+
```bash
|
|
473
|
+
# Connection management
|
|
474
|
+
anysite db add pg --type postgres --host localhost --database mydb --user app --password secret
|
|
475
|
+
anysite db add pg --type postgres --host localhost --database mydb --user app --password-env PGPASS
|
|
476
|
+
anysite db add ch --type clickhouse --host ch.example.com --port 8443 --database analytics --user app --password secret --ssl
|
|
477
|
+
anysite db add local --type sqlite --path ./data.db
|
|
478
|
+
anysite db add replica --type postgres --host replica.example.com --read-only
|
|
479
|
+
anysite db list
|
|
480
|
+
anysite db test pg
|
|
240
481
|
|
|
241
|
-
#
|
|
242
|
-
anysite
|
|
243
|
-
anysite
|
|
244
|
-
|
|
482
|
+
# Data operations
|
|
483
|
+
cat data.jsonl | anysite db insert pg --table users --stdin --auto-create
|
|
484
|
+
anysite db query pg --sql "SELECT * FROM users" --format table
|
|
485
|
+
anysite db query pg --sql "SELECT * FROM users" --format parquet --output users.parquet
|
|
486
|
+
anysite db query pg --sql "SELECT * FROM users" --format csv --output "reports/{{date}}/users.csv"
|
|
245
487
|
|
|
246
|
-
|
|
488
|
+
# Pipe API output to database
|
|
489
|
+
anysite api /api/linkedin/user user=satyanadella -q --format jsonl \
|
|
490
|
+
| anysite db insert pg --table profiles --stdin --auto-create
|
|
247
491
|
|
|
248
|
-
|
|
249
|
-
|
|
492
|
+
# Database discovery (schema introspection, sample data, LLM descriptions)
|
|
493
|
+
anysite db discover mydb # Discover schema
|
|
494
|
+
anysite db discover mydb --with-llm # Add LLM table/column descriptions
|
|
495
|
+
anysite db discover mydb --tables users,posts # Filter tables
|
|
496
|
+
anysite db discover mydb --exclude-tables _migrations
|
|
497
|
+
|
|
498
|
+
# View saved catalogs
|
|
499
|
+
anysite db catalog # List all catalogs
|
|
500
|
+
anysite db catalog mydb # Show full catalog
|
|
501
|
+
anysite db catalog mydb --table users # Show specific table
|
|
502
|
+
anysite db catalog mydb --json # JSON output for agents
|
|
503
|
+
```
|
|
250
504
|
|
|
251
|
-
|
|
252
|
-
- Include: `--fields "name,headline,urn.value"`
|
|
253
|
-
- Exclude: `--exclude "certifications,patents"`
|
|
254
|
-
- Presets: `--fields-preset minimal|contact|recruiting`
|
|
255
|
-
- Dot-notation for nested: `experience.company`, `urn.value`
|
|
505
|
+
Credentials: `--password` saves directly in `~/.anysite/connections.yaml`, `--password-env` references an env var. Direct value takes priority. LLM API keys follow the same pattern via `anysite llm setup`.
|
|
256
506
|
|
|
257
|
-
|
|
258
|
-
- `--on-error stop` — halt on first error (default)
|
|
259
|
-
- `--on-error skip` — continue processing, skip failures
|
|
260
|
-
- `--on-error retry` — auto-retry with backoff
|
|
507
|
+
Supported databases: SQLite, PostgreSQL, ClickHouse. ClickHouse uses `clickhouse-connect` driver (HTTP protocol, port 8123 default, 8443 for HTTPS/SSL).
|
|
261
508
|
|
|
262
|
-
|
|
263
|
-
CLI args > Environment vars (`ANYSITE_API_KEY`) > `~/.anysite/config.yaml` > defaults
|
|
509
|
+
## LLM Analysis Commands
|
|
264
510
|
|
|
265
|
-
|
|
511
|
+
Analyze collected dataset records using LLM. Requires `anysite llm setup` first.
|
|
266
512
|
|
|
267
|
-
|
|
513
|
+
Non-interactive setup (for agents):
|
|
268
514
|
```bash
|
|
269
|
-
anysite
|
|
270
|
-
|
|
271
|
-
anysite dataset collect company-intel/dataset.yaml --load-db pg
|
|
272
|
-
anysite db query pg --sql "SELECT c.name, COUNT(e.id) FROM companies c JOIN employees e ON e.companies_id = c.id GROUP BY c.name" --format table
|
|
273
|
-
|
|
274
|
-
# Set up daily schedule
|
|
275
|
-
anysite dataset schedule company-intel/dataset.yaml --incremental --load-db pg
|
|
276
|
-
# Add output to crontab
|
|
515
|
+
anysite llm setup --provider openai --api-key <key> --no-test
|
|
516
|
+
anysite llm setup --provider anthropic --api-key-env ANTHROPIC_API_KEY --model claude-sonnet-4-5-20250514 --no-test
|
|
277
517
|
```
|
|
278
518
|
|
|
279
|
-
### Batch lookup and save to CSV
|
|
280
519
|
```bash
|
|
281
|
-
anysite
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
--
|
|
520
|
+
anysite llm summarize dataset.yaml --source profiles --fields "name,headline" --format table
|
|
521
|
+
anysite llm classify dataset.yaml --source posts --categories "positive,negative,neutral"
|
|
522
|
+
anysite llm enrich dataset.yaml --source profiles \
|
|
523
|
+
--add "seniority:junior/mid/senior" --add "is_technical:boolean"
|
|
524
|
+
anysite llm generate dataset.yaml --source profiles \
|
|
525
|
+
--prompt "Write intro for {name} who works as {headline}" --temperature 0.7
|
|
526
|
+
anysite llm match dataset.yaml --source-a profiles --source-b companies --top-k 3
|
|
527
|
+
anysite llm deduplicate dataset.yaml --source profiles --key name --threshold 0.8
|
|
528
|
+
anysite llm cache-stats
|
|
529
|
+
anysite llm cache-clear
|
|
285
530
|
```
|
|
286
531
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
532
|
+
|
|
533
|
+
Use `anysite describe --search <keyword>` for more endpoints.
|
|
534
|
+
|
|
535
|
+
## Key Patterns
|
|
536
|
+
|
|
537
|
+
- **Output formats**: `--format json|jsonl|csv|table|parquet` (parquet requires `--output`)
|
|
538
|
+
- **Array params**: `keywords=a,b,c` auto-wraps as `["a","b","c"]`
|
|
539
|
+
- **Field selection**: `--fields "name,headline,urn.value"` (dot-notation for nested)
|
|
540
|
+
- **Error handling**: `--on-error stop|skip|retry`
|
|
541
|
+
- **Config priority**: CLI args > ENV vars > `~/.anysite/config.yaml` > defaults
|
|
542
|
+
|
|
543
|
+
## References
|
|
544
|
+
|
|
545
|
+
For detailed option tables and advanced configuration:
|
|
546
|
+
- [api-reference.md](references/api-reference.md) — all CLI options
|
|
547
|
+
- [llm-reference.md](references/llm-reference.md) — LLM provider config, cache, prompts
|
|
548
|
+
- [dataset-guide.md](references/dataset-guide.md) — full YAML schema, advanced features
|