atris 2.3.5 → 2.3.8

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: atris
3
- description: Codebase intelligence — generates structured navigation maps with file:line references so agents stop re-scanning the same files every session. Use when exploring code, answering "where is X?", or onboarding to a new codebase.
3
+ description: "Codebase intelligence — generates structured navigation maps with file:line references so agents stop re-scanning the same files every session. Use when exploring code, answering 'where is X?', or onboarding to a new codebase."
4
4
  version: 1.1.0
5
5
  requires:
6
6
  bins:
@@ -0,0 +1,248 @@
1
+ ---
2
+ name: create-member
3
+ description: "Create and manage AI team members using the MEMBER.md format. Use when the user wants to define a new AI role, set up a team member, create an agent persona, or work with team/MEMBER.md files."
4
+ version: 1.0.0
5
+ tags:
6
+ - team
7
+ - member
8
+ - agent
9
+ - persona
10
+ ---
11
+
12
+ # Member Creator
13
+
14
+ Create AI team members using the MEMBER.md format. A member is a directory that bundles persona, skills, tools, and context into a deployable AI worker.
15
+
16
+ ## What is MEMBER.md
17
+
18
+ MEMBER.md defines a complete AI team member. It composes existing standards (SKILL.md for capabilities, .mcp.json for tool servers) into a single portable unit.
19
+
20
+ Spec: https://github.com/atrislabs/member
21
+
22
+ ## Directory Structure
23
+
24
+ ```
25
+ team/<name>/
26
+ ├── MEMBER.md REQUIRED Persona + role + permissions
27
+ ├── skills/ OPTIONAL SKILL.md files (capabilities)
28
+ │ └── <skill>/
29
+ │ └── SKILL.md
30
+ ├── tools/ OPTIONAL MCP servers, API docs, CLI docs
31
+ │ ├── .mcp.json
32
+ │ └── <tool>.md
33
+ └── context/ OPTIONAL Domain knowledge (markdown)
34
+ └── *.md
35
+ ```
36
+
37
+ ## Creating a Member
38
+
39
+ When the user asks to create a team member, follow these steps:
40
+
41
+ ### Step 1: Ask what role
42
+
43
+ Ask the user:
44
+ - What role is this member? (e.g., SDR, support agent, code reviewer)
45
+ - What should they be able to do?
46
+ - What should they NOT be able to do?
47
+
48
+ ### Step 2: Create the directory
49
+
50
+ ```
51
+ team/<name>/
52
+ ├── MEMBER.md
53
+ ├── skills/
54
+ ├── tools/
55
+ └── context/
56
+ ```
57
+
58
+ Use kebab-case for the name. Create all four directories even if empty.
59
+
60
+ ### Step 3: Write MEMBER.md
61
+
62
+ Use this structure:
63
+
64
+ ```yaml
65
+ ---
66
+ name: <kebab-case-name>
67
+ role: <Human Readable Title>
68
+ description: <one line — what this member does>
69
+ version: 1.0.0
70
+
71
+ skills: []
72
+
73
+ permissions:
74
+ can-read: true
75
+ ---
76
+ ```
77
+
78
+ Below the frontmatter, write three sections:
79
+
80
+ **Persona** — How the member communicates. Tone, style, decision-making approach. Be specific — "direct and research-driven" is better than "professional and helpful."
81
+
82
+ **Workflow** — Numbered steps the member follows. This is the core operating procedure. Each step should be a concrete action.
83
+
84
+ **Rules** — Hard constraints. What the member must always or never do. Keep it to 3-5 rules.
85
+
86
+ ### Step 4: Add permissions
87
+
88
+ Common permission patterns:
89
+
90
+ ```yaml
91
+ # Read-only member (planner, researcher)
92
+ permissions:
93
+ can-read: true
94
+ can-execute: false
95
+
96
+ # Builder with guardrails
97
+ permissions:
98
+ can-read: true
99
+ can-execute: true
100
+ can-delete: false
101
+ approval-required: [delete, deploy]
102
+
103
+ # Full access (reviewer, admin)
104
+ permissions:
105
+ can-read: true
106
+ can-execute: true
107
+ can-approve: true
108
+ can-ship: true
109
+ ```
110
+
111
+ Permissions are declarations, not enforcement. They tell the agent what its boundaries are. The agent respects them because they're in its instructions.
112
+
113
+ ### Step 5: Add skills (optional)
114
+
115
+ If the member needs specific capabilities, create SKILL.md files:
116
+
117
+ ```
118
+ team/<name>/skills/<skill-name>/SKILL.md
119
+ ```
120
+
121
+ Each skill follows the standard SKILL.md format:
122
+
123
+ ```yaml
124
+ ---
125
+ name: <skill-name>
126
+ description: <what this skill does>
127
+ ---
128
+
129
+ # <Skill Name>
130
+
131
+ <Instructions for how to perform this capability>
132
+ ```
133
+
134
+ Update the member's frontmatter to list the skill:
135
+
136
+ ```yaml
137
+ skills:
138
+ - <skill-name>
139
+ ```
140
+
141
+ ### Step 6: Add context (optional)
142
+
143
+ Drop markdown files into `context/` with domain knowledge the member needs:
144
+ - Playbooks, SOPs, guidelines
145
+ - Customer profiles, ICPs
146
+ - Reference docs, templates
147
+
148
+ No special format. Just markdown files the member references.
149
+
150
+ ## Flat File Format
151
+
152
+ For simple members that just need a persona (no skills, tools, or context), use a flat file:
153
+
154
+ ```
155
+ team/<name>.md
156
+ ```
157
+
158
+ Same frontmatter, same format. Just no directory structure around it.
159
+
160
+ ## Detection
161
+
162
+ Add to your project's CLAUDE.md (or AGENTS.md for Codex):
163
+
164
+ ```markdown
165
+ ## Team
166
+
167
+ This project uses MEMBER.md team members in `team/`.
168
+ When activated as a specific member, read `team/<name>/MEMBER.md`.
169
+ ```
170
+
171
+ ## Multi-Agent Usage
172
+
173
+ Activate different members for different tasks:
174
+
175
+ ```
176
+ "Act as the navigator. Read team/navigator/MEMBER.md and plan this feature."
177
+ "Act as the validator. Read team/validator/MEMBER.md and review these changes."
178
+ ```
179
+
180
+ Each member gets its own persona, skills, permissions, and context.
181
+
182
+ ## Examples
183
+
184
+ ### Dev team member (code reviewer)
185
+
186
+ ```yaml
187
+ ---
188
+ name: reviewer
189
+ role: Code Reviewer
190
+ description: Reviews PRs for correctness, security, and style
191
+ version: 1.0.0
192
+ skills: []
193
+ permissions:
194
+ can-read: true
195
+ can-approve: true
196
+ can-execute: false
197
+ ---
198
+
199
+ ## Persona
200
+ Thorough but not pedantic. You catch real bugs, not style nits.
201
+ If something works and is readable, approve it.
202
+
203
+ ## Workflow
204
+ 1. Read the diff
205
+ 2. Check for bugs, security issues, breaking changes
206
+ 3. Approve or request specific changes (no vague feedback)
207
+
208
+ ## Rules
209
+ 1. Never block on style alone
210
+ 2. Every comment must be actionable
211
+ 3. If unsure, approve with a note
212
+ ```
213
+
214
+ ### Business role (SDR)
215
+
216
+ ```yaml
217
+ ---
218
+ name: sdr
219
+ role: Sales Development Rep
220
+ description: Outbound prospecting and lead qualification
221
+ version: 1.0.0
222
+ skills:
223
+ - email-outreach
224
+ - lead-research
225
+ permissions:
226
+ can-draft: true
227
+ can-send: false
228
+ approval-required: [send, delete]
229
+ tools:
230
+ - hubspot
231
+ - apollo
232
+ ---
233
+
234
+ ## Persona
235
+ Research-driven. Every email references something specific about
236
+ the prospect. If you can't find a hook, don't send.
237
+
238
+ ## Workflow
239
+ 1. Research the lead
240
+ 2. Qualify against ICP (context/icp.md)
241
+ 3. Draft personalized sequence
242
+ 4. Flag for human approval
243
+
244
+ ## Rules
245
+ 1. Never send without approval
246
+ 2. Every email must reference something specific
247
+ 3. Log everything to CRM
248
+ ```
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: drive
3
3
  description: Google Drive integration via AtrisOS API. Browse, search, read, upload files and work with Google Sheets. Use when user asks about Drive, files, docs, sheets, or spreadsheets.
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  tags:
6
6
  - drive
7
7
  - backend
@@ -199,6 +199,29 @@ curl -s -X POST "https://api.atris.ai/api/integrations/google-drive/files" \
199
199
  }'
200
200
  ```
201
201
 
202
+ ### Update Existing File
203
+ ```bash
204
+ curl -s -X PUT "https://api.atris.ai/api/integrations/google-drive/files/{file_id}" \
205
+ -H "Authorization: Bearer $TOKEN" \
206
+ -H "Content-Type: application/json" \
207
+ -d '{
208
+ "content": "Updated file content here",
209
+ "mime_type": "text/plain"
210
+ }'
211
+ ```
212
+
213
+ **Update content and rename:**
214
+ ```bash
215
+ curl -s -X PUT "https://api.atris.ai/api/integrations/google-drive/files/{file_id}" \
216
+ -H "Authorization: Bearer $TOKEN" \
217
+ -H "Content-Type: application/json" \
218
+ -d '{
219
+ "content": "New content",
220
+ "mime_type": "text/plain",
221
+ "name": "renamed-file.txt"
222
+ }'
223
+ ```
224
+
202
225
  ---
203
226
 
204
227
  ## Google Sheets
@@ -299,6 +322,14 @@ curl -s -X POST "https://api.atris.ai/api/integrations/google-drive/sheets/{spre
299
322
  3. **Confirm with user**: "Upload {filename} to Drive?"
300
323
  4. Upload: `POST /google-drive/files` with `{name, content, mime_type}`
301
324
 
325
+ ### "Edit a file on Drive"
326
+ 1. Run bootstrap
327
+ 2. Find the file: `GET /google-drive/search?q=FILENAME`
328
+ 3. Read current content: `GET /google-drive/files/{id}/export?mime_type=text/plain`
329
+ 4. Make edits
330
+ 5. **Show user the changes for approval**
331
+ 6. Update: `PUT /google-drive/files/{id}` with `{content, mime_type}`
332
+
302
333
  ---
303
334
 
304
335
  ## Error Handling
@@ -356,8 +387,13 @@ curl -s -X POST "https://api.atris.ai/api/integrations/google-drive/sheets/{id}/
356
387
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
357
388
  -d '{"range":"Sheet1","values":[["Alice",95]]}'
358
389
 
359
- # Upload a file
390
+ # Upload a new file
360
391
  curl -s -X POST "https://api.atris.ai/api/integrations/google-drive/files" \
361
392
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
362
393
  -d '{"name":"notes.txt","content":"Hello world","mime_type":"text/plain"}'
394
+
395
+ # Update an existing file
396
+ curl -s -X PUT "https://api.atris.ai/api/integrations/google-drive/files/{file_id}" \
397
+ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
398
+ -d '{"content":"Updated content","mime_type":"text/plain"}'
363
399
  ```
@@ -250,6 +250,17 @@ curl -s -X DELETE "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}
250
250
  -H "Authorization: Bearer $TOKEN"
251
251
  ```
252
252
 
253
+ ### Mark as Read / Unread
254
+ ```bash
255
+ # Mark as read
256
+ curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/read" \
257
+ -H "Authorization: Bearer $TOKEN"
258
+
259
+ # Mark as unread
260
+ curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/unread" \
261
+ -H "Authorization: Bearer $TOKEN"
262
+ ```
263
+
253
264
  ### Archive Email
254
265
  ```bash
255
266
  # Single message
@@ -263,6 +274,19 @@ curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/batch-arch
263
274
  -d '{"message_ids": ["id1", "id2", "id3"]}'
264
275
  ```
265
276
 
277
+ ### Trash Email
278
+ ```bash
279
+ # Single message
280
+ curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/trash" \
281
+ -H "Authorization: Bearer $TOKEN"
282
+
283
+ # Batch trash
284
+ curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/batch-trash" \
285
+ -H "Authorization: Bearer $TOKEN" \
286
+ -H "Content-Type: application/json" \
287
+ -d '{"message_ids": ["id1", "id2", "id3"]}'
288
+ ```
289
+
266
290
  ### Check Status
267
291
  ```bash
268
292
  curl -s "https://api.atris.ai/api/integrations/gmail/status" \
@@ -410,6 +434,12 @@ curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts" \
410
434
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
411
435
  -d '{"to":"email@example.com","subject":"Hi","body":"Draft text"}'
412
436
 
437
+ # Mark as read
438
+ curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/read" -H "Authorization: Bearer $TOKEN"
439
+
440
+ # Trash an email
441
+ curl -s -X POST "https://api.atris.ai/api/integrations/gmail/messages/{message_id}/trash" -H "Authorization: Bearer $TOKEN"
442
+
413
443
  # Send a draft
414
444
  curl -s -X POST "https://api.atris.ai/api/integrations/gmail/drafts/{draft_id}/send" \
415
445
  -H "Authorization: Bearer $TOKEN"
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: slack
3
3
  description: Slack integration via AtrisOS API. Read messages, send as yourself, search conversations, manage DMs. Use when user asks about Slack, messages, channels, or team communication.
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  tags:
6
6
  - slack
7
7
  - backend
@@ -187,6 +187,14 @@ curl -s "https://api.atris.ai/api/integrations/slack/users" \
187
187
  -H "Authorization: Bearer $TOKEN"
188
188
  ```
189
189
 
190
+ ### Search Users
191
+ ```bash
192
+ curl -s "https://api.atris.ai/api/integrations/slack/users/search?q=justin" \
193
+ -H "Authorization: Bearer $TOKEN"
194
+ ```
195
+
196
+ Searches by name, display name, or email. Much faster than pulling the full user list.
197
+
190
198
  ### Send as Bot
191
199
  ```bash
192
200
  curl -s -X POST "https://api.atris.ai/api/integrations/slack/test-send" \
@@ -223,9 +231,9 @@ curl -s -X DELETE "https://api.atris.ai/api/integrations/slack" \
223
231
 
224
232
  ### "Send a message to someone"
225
233
  1. Run bootstrap
226
- 2. Find the user: `GET /slack/users` (search by name/email)
234
+ 2. Find the user: `GET /slack/users/search?q=NAME`
227
235
  3. **Show user the draft for approval**
228
- 4. Send DM: `POST /slack/me/dm` with `{user_id, text}`
236
+ 4. Send DM: `POST /slack/me/dm` with `{slack_user_id, text}`
229
237
  5. Confirm: "Message sent!"
230
238
 
231
239
  ### "Reply in a channel"
@@ -243,7 +251,7 @@ curl -s -X DELETE "https://api.atris.ai/api/integrations/slack" \
243
251
 
244
252
  ### "What did [person] say to me?"
245
253
  1. Run bootstrap
246
- 2. List users: `GET /slack/users` (find user ID)
254
+ 2. Find user: `GET /slack/users/search?q=NAME` (get user ID)
247
255
  3. List DMs: `GET /slack/me/dms` (find DM channel with that user)
248
256
  4. Read messages: `GET /slack/me/messages/{channel_id}`
249
257
  5. Display conversation
@@ -317,4 +325,7 @@ curl -s "https://api.atris.ai/api/integrations/slack/me/search?q=project+update"
317
325
 
318
326
  # List workspace users
319
327
  curl -s "https://api.atris.ai/api/integrations/slack/users" -H "Authorization: Bearer $TOKEN"
328
+
329
+ # Search users by name
330
+ curl -s "https://api.atris.ai/api/integrations/slack/users/search?q=justin" -H "Authorization: Bearer $TOKEN"
320
331
  ```
@@ -0,0 +1,234 @@
1
+ ---
2
+ name: x-search
3
+ description: "X/Twitter search via xAI Grok API. Use when user wants to search tweets, monitor topics, find viral posts, or run social listening. Costs 5 credits per search. Triggers on x search, tweet search, twitter search, social listening, revenue intel, viral tweets."
4
+ version: 2.0.0
5
+ tags:
6
+ - x-search
7
+ - social
8
+ - research
9
+ ---
10
+
11
+ # X Search
12
+
13
+ > Drop this in `~/.claude/skills/x-search/SKILL.md` and Claude Code becomes your X/Twitter intelligence tool.
14
+
15
+ ## Bootstrap (ALWAYS Run First)
16
+
17
+ Before any X search operation, run this bootstrap to ensure everything is set up:
18
+
19
+ ```bash
20
+ #!/bin/bash
21
+ set -e
22
+
23
+ # 1. Check if atris CLI is installed
24
+ if ! command -v atris &> /dev/null; then
25
+ echo "Installing atris CLI..."
26
+ npm install -g atris
27
+ fi
28
+
29
+ # 2. Check if logged in to AtrisOS
30
+ if [ ! -f ~/.atris/credentials.json ]; then
31
+ echo "Not logged in to AtrisOS."
32
+ echo ""
33
+ echo "Option 1 (interactive): Run 'atris login' and follow prompts"
34
+ echo "Option 2 (non-interactive): Get token from https://atris.ai/auth/cli"
35
+ echo " Then run: atris login --token YOUR_TOKEN"
36
+ echo ""
37
+ exit 1
38
+ fi
39
+
40
+ # 3. Extract token
41
+ if command -v node &> /dev/null; then
42
+ TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
43
+ elif command -v python3 &> /dev/null; then
44
+ TOKEN=$(python3 -c "import json,os; print(json.load(open(os.path.expanduser('~/.atris/credentials.json')))['token'])")
45
+ elif command -v jq &> /dev/null; then
46
+ TOKEN=$(jq -r '.token' ~/.atris/credentials.json)
47
+ else
48
+ echo "Error: Need node, python3, or jq to read credentials"
49
+ exit 1
50
+ fi
51
+
52
+ # 4. Quick auth check
53
+ STATUS=$(curl -s "https://api.atris.ai/api/me" \
54
+ -H "Authorization: Bearer $TOKEN")
55
+
56
+ if echo "$STATUS" | grep -q "Token expired\|Not authenticated\|Unauthorized"; then
57
+ echo "Token expired. Please re-authenticate:"
58
+ echo " Run: atris login --force"
59
+ exit 1
60
+ fi
61
+
62
+ echo "Ready. X Search is available (5 credits per search)."
63
+ export ATRIS_TOKEN="$TOKEN"
64
+ ```
65
+
66
+ ---
67
+
68
+ ## API Reference
69
+
70
+ Base: `https://api.atris.ai/api/x-search`
71
+
72
+ All requests require: `-H "Authorization: Bearer $TOKEN"`
73
+
74
+ ### Get Token (after bootstrap)
75
+ ```bash
76
+ TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
77
+ ```
78
+
79
+ ### Search X/Twitter
80
+ ```bash
81
+ curl -s -X POST "https://api.atris.ai/api/x-search/search" \
82
+ -H "Authorization: Bearer $TOKEN" \
83
+ -H "Content-Type: application/json" \
84
+ -d '{
85
+ "query": "\"CRM is dead\" OR \"Salesforce alternative\"",
86
+ "limit": 10
87
+ }'
88
+ ```
89
+
90
+ **With date filter** (last N days only):
91
+ ```bash
92
+ curl -s -X POST "https://api.atris.ai/api/x-search/search" \
93
+ -H "Authorization: Bearer $TOKEN" \
94
+ -H "Content-Type: application/json" \
95
+ -d '{
96
+ "query": "AI agents replacing SaaS",
97
+ "limit": 10,
98
+ "days_back": 7
99
+ }'
100
+ ```
101
+
102
+ **Response:**
103
+ ```json
104
+ {
105
+ "status": "success",
106
+ "credits_used": 5,
107
+ "credits_remaining": 995,
108
+ "data": {
109
+ "content": "1. @levelsio: AI agents are replacing...",
110
+ "citations": ["https://x.com/levelsio/status/..."],
111
+ "usage": {"prompt_tokens": 200, "completion_tokens": 800}
112
+ }
113
+ }
114
+ ```
115
+
116
+ ### Research a Person
117
+ ```bash
118
+ curl -s -X POST "https://api.atris.ai/api/x-search/research-person" \
119
+ -H "Authorization: Bearer $TOKEN" \
120
+ -H "Content-Type: application/json" \
121
+ -d '{
122
+ "name": "Leah Bonvissuto",
123
+ "handle": "leahbon",
124
+ "company": "Presentr",
125
+ "context": "Interested in revenue intelligence and AI for GTM"
126
+ }'
127
+ ```
128
+
129
+ **Response:**
130
+ ```json
131
+ {
132
+ "status": "success",
133
+ "credits_used": 5,
134
+ "credits_remaining": 990,
135
+ "data": {
136
+ "content": "### 1. Profile\n**Name:** Leah Bonvissuto\n...",
137
+ "citations": ["https://x.com/..."],
138
+ "usage": {"prompt_tokens": 300, "completion_tokens": 1200}
139
+ }
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Workflows
146
+
147
+ ### "Search X for tweets about a topic"
148
+ 1. Run bootstrap
149
+ 2. Search: `POST /x-search/search` with `{query, limit}`
150
+ 3. Display results: tweet text, author, engagement, links
151
+
152
+ ### "Find tweets from the last week about X"
153
+ 1. Run bootstrap
154
+ 2. Search with date filter: `POST /x-search/search` with `{query, limit, days_back: 7}`
155
+ 3. Display results sorted by engagement
156
+
157
+ ### "Research a person before a meeting"
158
+ 1. Run bootstrap
159
+ 2. Research: `POST /x-search/research-person` with `{name, handle, company, context}`
160
+ 3. Display profile, background, talking points
161
+
162
+ ### "Monitor keyword clusters for revenue intel"
163
+ 1. Run bootstrap
164
+ 2. Run multiple searches across keyword clusters:
165
+ - `"CRM is dead" OR "Salesforce is dead" OR "HubSpot sucks"`
166
+ - `"revenue operations" (broken OR frustrated OR replacing)`
167
+ - `(founder OR CEO) "tech stack" (consolidating OR ripping out)`
168
+ 3. Each search costs 5 credits
169
+ 4. Combine results, rank by engagement, draft replies
170
+
171
+ ### "Find viral tweets in my industry"
172
+ 1. Run bootstrap
173
+ 2. Search with engagement filter: `POST /x-search/search` with query including `min_faves:50`
174
+ 3. Display top tweets sorted by likes/retweets
175
+
176
+ ---
177
+
178
+ ## Query Tips
179
+
180
+ | Goal | Query Example |
181
+ |------|--------------|
182
+ | Specific phrase | `"revenue operations"` |
183
+ | OR logic | `"CRM is dead" OR "Salesforce alternative"` |
184
+ | From a user | `from:levelsio` |
185
+ | High engagement | `"AI agents" min_faves:50` |
186
+ | Exclude retweets | `"your query" -is:retweet` |
187
+ | Multiple keywords | `(founder OR CEO) ("AI adoption" OR "AI native")` |
188
+
189
+ ---
190
+
191
+ ## Billing
192
+
193
+ - Every search costs **5 credits** (flat)
194
+ - 1 credit = $0.01, so 1 search = $0.05
195
+ - Research person also costs 5 credits
196
+ - Credits are deducted server-side before the search runs
197
+ - If insufficient credits, returns `402 Insufficient credits`
198
+
199
+ ---
200
+
201
+ ## Error Handling
202
+
203
+ | Error | Meaning | Solution |
204
+ |-------|---------|----------|
205
+ | `401 Not authenticated` | Invalid/expired token | Run `atris login` |
206
+ | `402 Insufficient credits` | Not enough credits | Purchase credits at atris.ai |
207
+ | `502 Search failed` | xAI API issue | Retry in a few seconds |
208
+
209
+ ---
210
+
211
+ ## Quick Reference
212
+
213
+ ```bash
214
+ # Setup (one time)
215
+ npm install -g atris && atris login
216
+
217
+ # Get token
218
+ TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
219
+
220
+ # Search tweets
221
+ curl -s -X POST "https://api.atris.ai/api/x-search/search" \
222
+ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
223
+ -d '{"query": "AI agents", "limit": 10}'
224
+
225
+ # Search last 7 days only
226
+ curl -s -X POST "https://api.atris.ai/api/x-search/search" \
227
+ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
228
+ -d '{"query": "AI agents", "limit": 10, "days_back": 7}'
229
+
230
+ # Research a person
231
+ curl -s -X POST "https://api.atris.ai/api/x-search/research-person" \
232
+ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
233
+ -d '{"name": "John Doe", "handle": "johndoe", "company": "Acme"}'
234
+ ```