atris 2.3.7 → 2.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/atris/skills/magic-inbox/SKILL.md +216 -0
- package/atris/skills/x-search/SKILL.md +198 -108
- package/atris/team/_template/MEMBER.md +16 -0
- package/atris/team/brainstormer/MEMBER.md +6 -1
- package/atris/team/executor/MEMBER.md +6 -1
- package/atris/team/launcher/MEMBER.md +6 -1
- package/atris/team/navigator/MEMBER.md +6 -1
- package/atris/team/researcher/MEMBER.md +6 -1
- package/atris/team/validator/MEMBER.md +6 -1
- package/commands/init.js +35 -6
- package/commands/member.js +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: magic-inbox
|
|
3
|
+
description: "Autonomous inbox agent. Scores emails, drafts replies, archives noise, Slack summaries. Uses Gmail + Calendar + Slack + your context. Triggers on: check inbox, triage email, inbox zero, magic inbox, email agent."
|
|
4
|
+
version: 2.0.0
|
|
5
|
+
tags:
|
|
6
|
+
- inbox
|
|
7
|
+
- email
|
|
8
|
+
- productivity
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Magic Inbox
|
|
12
|
+
|
|
13
|
+
You are an inbox agent. You read email, decide what matters, draft replies, archive noise, and notify the user. You do this using your own intelligence — no separate LLM calls needed. You ARE the model.
|
|
14
|
+
|
|
15
|
+
## Bootstrap (ALWAYS Run First)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
#!/bin/bash
|
|
19
|
+
set -e
|
|
20
|
+
|
|
21
|
+
if [ ! -f ~/.atris/credentials.json ]; then
|
|
22
|
+
echo "Not logged in. Run: atris login"
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
if command -v node &> /dev/null; then
|
|
27
|
+
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
|
|
28
|
+
elif command -v python3 &> /dev/null; then
|
|
29
|
+
TOKEN=$(python3 -c "import json,os; print(json.load(open(os.path.expanduser('~/.atris/credentials.json')))['token'])")
|
|
30
|
+
else
|
|
31
|
+
TOKEN=$(jq -r '.token' ~/.atris/credentials.json)
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
echo "Ready."
|
|
35
|
+
export ATRIS_TOKEN="$TOKEN"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Context Files
|
|
41
|
+
|
|
42
|
+
Before triaging, ALWAYS read these context files from the skill directory. They tell you who matters and how to behave.
|
|
43
|
+
|
|
44
|
+
- `~/.claude/skills/magic-inbox/contacts.md` — priority contacts and noise patterns
|
|
45
|
+
- `~/.claude/skills/magic-inbox/priorities.md` — current work streams
|
|
46
|
+
- `~/.claude/skills/magic-inbox/voice.md` — how to write replies
|
|
47
|
+
- `~/.claude/skills/magic-inbox/rules.md` — hard rules that override everything
|
|
48
|
+
- `~/.claude/skills/magic-inbox/log.md` — action log (append after each run)
|
|
49
|
+
|
|
50
|
+
Read ALL context files before scoring. They are your memory.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## The Flow
|
|
55
|
+
|
|
56
|
+
### Step 1: Fetch everything (one call)
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
curl -s "https://api.atris.ai/api/magic-inbox/fetch?max_emails=30" \
|
|
60
|
+
-H "Authorization: Bearer $ATRIS_TOKEN"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Returns email + calendar + slack in one structured response:
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"email": {
|
|
67
|
+
"messages": [
|
|
68
|
+
{"id": "...", "thread_id": "...", "from": "...", "subject": "...", "snippet": "...", "has_unsubscribe": false}
|
|
69
|
+
],
|
|
70
|
+
"count": 20
|
|
71
|
+
},
|
|
72
|
+
"calendar": {
|
|
73
|
+
"events": [
|
|
74
|
+
{"summary": "Meeting with Grace", "start": "...", "attendees": ["grace@pallet.com"]}
|
|
75
|
+
],
|
|
76
|
+
"count": 1
|
|
77
|
+
},
|
|
78
|
+
"slack": {
|
|
79
|
+
"dms": [
|
|
80
|
+
{"channel_id": "...", "user_id": "...", "messages": [{"text": "...", "user": "...", "ts": "..."}]}
|
|
81
|
+
],
|
|
82
|
+
"count": 3
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Step 2: Score each email
|
|
88
|
+
|
|
89
|
+
Using YOUR judgment, score each email:
|
|
90
|
+
|
|
91
|
+
| Priority | Meaning | Action |
|
|
92
|
+
|----------|---------|--------|
|
|
93
|
+
| 1 | Drop everything | Draft reply immediately |
|
|
94
|
+
| 2 | Today | Draft reply |
|
|
95
|
+
| 3 | This week | Flag for later |
|
|
96
|
+
| 4 | Whenever | Star as read-later |
|
|
97
|
+
| 5 | Noise | Archive |
|
|
98
|
+
|
|
99
|
+
**Scoring signals:**
|
|
100
|
+
- Check `contacts.md` — is sender a priority contact?
|
|
101
|
+
- Check `priorities.md` — is topic related to current work?
|
|
102
|
+
- Has `has_unsubscribe: true` → almost certainly 4-5
|
|
103
|
+
- Addressed directly (not a list) → lean toward 1-3
|
|
104
|
+
- From a real person at a real company → lean toward 1-3
|
|
105
|
+
- Cold outreach from unknown `.info`/`.xyz` domain → 5
|
|
106
|
+
- Calendar shows meeting with sender today → bump priority up
|
|
107
|
+
|
|
108
|
+
### Step 3: Take action (one call)
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
curl -s -X POST "https://api.atris.ai/api/magic-inbox/act" \
|
|
112
|
+
-H "Authorization: Bearer $ATRIS_TOKEN" \
|
|
113
|
+
-H "Content-Type: application/json" \
|
|
114
|
+
-d '{
|
|
115
|
+
"drafts": [
|
|
116
|
+
{"to": "sender@email.com", "subject": "Re: Subject", "body": "Reply text", "thread_id": "..."}
|
|
117
|
+
],
|
|
118
|
+
"archive": ["msg_id_1", "msg_id_2"],
|
|
119
|
+
"star": ["msg_id_3"],
|
|
120
|
+
"mark_read": ["msg_id_4"]
|
|
121
|
+
}'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"status": "ok",
|
|
128
|
+
"drafts_created": 2,
|
|
129
|
+
"archived": 16,
|
|
130
|
+
"starred": 6,
|
|
131
|
+
"read": 0,
|
|
132
|
+
"details": { ... }
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Step 4: Present the briefing
|
|
137
|
+
|
|
138
|
+
Show the user a clean summary (see format below).
|
|
139
|
+
|
|
140
|
+
### Step 5: Update the log
|
|
141
|
+
|
|
142
|
+
Append to `~/.claude/skills/magic-inbox/log.md` what you did this run.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Summary Format
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
Inbox Triage — 23 emails processed
|
|
150
|
+
|
|
151
|
+
Needs you (2):
|
|
152
|
+
- Suhas (via Maya) — FDE candidate intro. Draft ready. [check drafts]
|
|
153
|
+
- Michelle at Stripe — Build Day March 4, demo opportunity. Draft ready.
|
|
154
|
+
|
|
155
|
+
This week (1):
|
|
156
|
+
- Kim (angel, 9x founder) — intro.co intro. Worth a call.
|
|
157
|
+
|
|
158
|
+
Handled (20):
|
|
159
|
+
- 12 archived (newsletters, marketing)
|
|
160
|
+
- 5 starred as read-later (events, notifications)
|
|
161
|
+
- 3 npm/transactional archived
|
|
162
|
+
|
|
163
|
+
Inbox: 3 emails remaining.
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Rules for summary:
|
|
167
|
+
- Use real names, not email addresses
|
|
168
|
+
- Include WHY something is important (from context files)
|
|
169
|
+
- For drafts, tell the user to check Gmail drafts
|
|
170
|
+
- Be concise — this is a briefing, not a report
|
|
171
|
+
- Show the count reduction (was X, now Y)
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Draft Style
|
|
176
|
+
|
|
177
|
+
Follow `voice.md`. General rules:
|
|
178
|
+
|
|
179
|
+
- Casual, direct, no fluff
|
|
180
|
+
- No "I hope this email finds you well"
|
|
181
|
+
- No "Just circling back" or "Per my last email"
|
|
182
|
+
- Short — 2-4 sentences max
|
|
183
|
+
- Match the energy of the incoming email
|
|
184
|
+
- For intros: be warm, suggest a time, keep it to 2 sentences
|
|
185
|
+
- For RSVPs: be enthusiastic, confirm attendance
|
|
186
|
+
- For business: be specific about next steps
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Rules (from rules.md)
|
|
191
|
+
|
|
192
|
+
Hard rules that override everything:
|
|
193
|
+
1. NEVER auto-send. Always save as draft for user review.
|
|
194
|
+
2. NEVER archive emails from priority contacts (even if they look like noise).
|
|
195
|
+
3. NEVER reply to emails with List-Unsubscribe header.
|
|
196
|
+
4. Always show the user what you did — no silent actions.
|
|
197
|
+
5. If unsure about priority, err toward keeping it (don't archive).
|
|
198
|
+
6. Log every action to log.md.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## API Quick Reference
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Get token (bootstrap does this)
|
|
206
|
+
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
|
|
207
|
+
|
|
208
|
+
# Fetch inbox (email + calendar + slack)
|
|
209
|
+
curl -s "https://api.atris.ai/api/magic-inbox/fetch?max_emails=30" -H "Authorization: Bearer $TOKEN"
|
|
210
|
+
|
|
211
|
+
# Execute actions (drafts + archive + star)
|
|
212
|
+
curl -s -X POST "https://api.atris.ai/api/magic-inbox/act" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"drafts":[...],"archive":[...],"star":[...]}'
|
|
213
|
+
|
|
214
|
+
# Read a specific email (when snippet isn't enough)
|
|
215
|
+
curl -s "https://api.atris.ai/api/integrations/gmail/messages/{id}" -H "Authorization: Bearer $TOKEN"
|
|
216
|
+
```
|
|
@@ -1,144 +1,234 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: x-search
|
|
3
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:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
tags:
|
|
6
6
|
- x-search
|
|
7
7
|
- social
|
|
8
8
|
- research
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
#
|
|
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
|
+
---
|
|
12
67
|
|
|
13
|
-
|
|
68
|
+
## API Reference
|
|
14
69
|
|
|
15
|
-
|
|
70
|
+
Base: `https://api.atris.ai/api/x-search`
|
|
16
71
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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)")
|
|
20
77
|
```
|
|
21
78
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
+
```
|
|
26
89
|
|
|
27
|
-
|
|
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
|
+
```
|
|
28
101
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
```
|
|
33
115
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
+
}'
|
|
39
127
|
```
|
|
40
128
|
|
|
41
|
-
|
|
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
|
+
```
|
|
42
142
|
|
|
43
|
-
|
|
44
|
-
from xai_sdk.chat import user as xai_user
|
|
143
|
+
---
|
|
45
144
|
|
|
46
|
-
|
|
47
|
-
|
|
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
|
|
48
175
|
|
|
49
|
-
|
|
50
|
-
model="grok-4-1-fast",
|
|
51
|
-
tools=[tools.x_search()],
|
|
52
|
-
)
|
|
176
|
+
---
|
|
53
177
|
|
|
54
|
-
|
|
178
|
+
## Query Tips
|
|
55
179
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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")` |
|
|
62
188
|
|
|
63
|
-
|
|
189
|
+
---
|
|
64
190
|
|
|
65
|
-
|
|
66
|
-
for response, chunk in chat.stream():
|
|
67
|
-
if chunk.content:
|
|
68
|
-
content += chunk.content
|
|
69
|
-
print(content)
|
|
70
|
-
```
|
|
191
|
+
## Billing
|
|
71
192
|
|
|
72
|
-
|
|
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`
|
|
73
198
|
|
|
74
|
-
|
|
75
|
-
from atris.team.gtm.skills.revenue_intel import run_digest, format_for_slack
|
|
199
|
+
---
|
|
76
200
|
|
|
77
|
-
|
|
78
|
-
# Cost: 5 credits per cluster = 25 credits total
|
|
79
|
-
result = await run_digest(
|
|
80
|
-
days_back=1,
|
|
81
|
-
user_id=USER_ID,
|
|
82
|
-
draft_count=5,
|
|
83
|
-
)
|
|
201
|
+
## Error Handling
|
|
84
202
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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 |
|
|
88
208
|
|
|
89
|
-
|
|
90
|
-
slack_msg = await format_for_slack(result)
|
|
91
|
-
```
|
|
209
|
+
---
|
|
92
210
|
|
|
93
|
-
##
|
|
211
|
+
## Quick Reference
|
|
94
212
|
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"industry_pain": '"your industry" (frustrated OR broken OR replacing OR ripping out)',
|
|
99
|
-
"thought_leaders": '(founder OR CEO OR CTO) ("your topic" OR "related topic") min_faves:10',
|
|
100
|
-
}
|
|
213
|
+
```bash
|
|
214
|
+
# Setup (one time)
|
|
215
|
+
npm install -g atris && atris login
|
|
101
216
|
|
|
102
|
-
|
|
103
|
-
|
|
217
|
+
# Get token
|
|
218
|
+
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
|
|
104
219
|
|
|
105
|
-
|
|
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}'
|
|
106
224
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
| Max ($200/mo) | unlimited | unlimited |
|
|
118
|
-
| Credit pack ($10) | 1,000 | 200 |
|
|
119
|
-
|
|
120
|
-
## Cost Breakdown
|
|
121
|
-
|
|
122
|
-
| Component | Cost to us | What it does |
|
|
123
|
-
|-----------|-----------|--------------|
|
|
124
|
-
| xAI x_search tool | $0.005/call | Searches X, returns batch of tweets |
|
|
125
|
-
| grok-4-1-fast tokens | ~$0.003/call | Processes and formats results |
|
|
126
|
-
| Total per search | ~$0.008 | Raw cost |
|
|
127
|
-
| We charge | $0.05 (5 credits) | 84% margin |
|
|
128
|
-
|
|
129
|
-
## Key Files
|
|
130
|
-
|
|
131
|
-
| File | What |
|
|
132
|
-
|------|------|
|
|
133
|
-
| `backend/clients/xai.py` | XAIClient + bill_xai_action() |
|
|
134
|
-
| `atris/team/gtm/skills/revenue_intel.py` | Multi-cluster digest pipeline |
|
|
135
|
-
| `backend/tools/core/reply_guy_tool.py` | Reply generation tool (bills 5 credits) |
|
|
136
|
-
| `backend/tools/integrations/research_tweet_tool.py` | Research + tweet tool (bills 5 credits) |
|
|
137
|
-
|
|
138
|
-
## Rules
|
|
139
|
-
|
|
140
|
-
1. Always bill before searching — never search without `bill_xai_action()`
|
|
141
|
-
2. Date filtering is prompt-based, not API-level — include explicit date cutoff in prompt
|
|
142
|
-
3. Use `min_faves:N` in queries to filter low-engagement noise
|
|
143
|
-
4. Never auto-post tweets — always require user approval
|
|
144
|
-
5. Internal usage (no user_id) skips billing — platform absorbs cost
|
|
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
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: template-member
|
|
3
|
+
role: Replace with role title
|
|
4
|
+
description: Replace with one-line description of what this member does.
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
|
|
7
|
+
skills: []
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
can-read: true
|
|
11
|
+
approval-required: []
|
|
12
|
+
|
|
13
|
+
tools: []
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Insert persona, workflow, and rules below
|
|
@@ -4,13 +4,18 @@ role: Idea Shaper
|
|
|
4
4
|
description: Shape ideas, explore possibilities, adapt to user depth
|
|
5
5
|
version: 1.0.0
|
|
6
6
|
|
|
7
|
-
skills:
|
|
7
|
+
skills:
|
|
8
|
+
- idea-shaping
|
|
9
|
+
- reality-mapping
|
|
8
10
|
|
|
9
11
|
permissions:
|
|
10
12
|
can-read: true
|
|
11
13
|
can-plan: false
|
|
12
14
|
can-execute: false
|
|
13
15
|
can-approve: false
|
|
16
|
+
approval-required: []
|
|
17
|
+
|
|
18
|
+
tools: []
|
|
14
19
|
---
|
|
15
20
|
|
|
16
21
|
# Brainstormer — Idea & Reality Shaper
|
|
@@ -4,13 +4,18 @@ role: Builder
|
|
|
4
4
|
description: Execute from build specs, one step at a time
|
|
5
5
|
version: 1.0.0
|
|
6
6
|
|
|
7
|
-
skills:
|
|
7
|
+
skills:
|
|
8
|
+
- code-writer
|
|
9
|
+
- test-runner
|
|
8
10
|
|
|
9
11
|
permissions:
|
|
10
12
|
can-read: true
|
|
11
13
|
can-plan: false
|
|
12
14
|
can-execute: true
|
|
13
15
|
can-approve: false
|
|
16
|
+
approval-required: [delete, refactor-outside-scope]
|
|
17
|
+
|
|
18
|
+
tools: []
|
|
14
19
|
---
|
|
15
20
|
|
|
16
21
|
# Executor — Builder
|
|
@@ -4,7 +4,9 @@ role: Closer
|
|
|
4
4
|
description: Document, capture learnings, publish, celebrate
|
|
5
5
|
version: 1.0.0
|
|
6
6
|
|
|
7
|
-
skills:
|
|
7
|
+
skills:
|
|
8
|
+
- doc-writer
|
|
9
|
+
- publish-helper
|
|
8
10
|
|
|
9
11
|
permissions:
|
|
10
12
|
can-read: true
|
|
@@ -12,6 +14,9 @@ permissions:
|
|
|
12
14
|
can-execute: false
|
|
13
15
|
can-approve: false
|
|
14
16
|
can-ship: true
|
|
17
|
+
approval-required: []
|
|
18
|
+
|
|
19
|
+
tools: []
|
|
15
20
|
---
|
|
16
21
|
|
|
17
22
|
# Launcher — The Closer
|
|
@@ -4,13 +4,18 @@ role: Planner
|
|
|
4
4
|
description: Transform messy human intent into precise execution plans
|
|
5
5
|
version: 1.0.0
|
|
6
6
|
|
|
7
|
-
skills:
|
|
7
|
+
skills:
|
|
8
|
+
- codebase-scout
|
|
9
|
+
- feature-spec
|
|
8
10
|
|
|
9
11
|
permissions:
|
|
10
12
|
can-read: true
|
|
11
13
|
can-plan: true
|
|
12
14
|
can-execute: false
|
|
13
15
|
can-approve: false
|
|
16
|
+
approval-required: []
|
|
17
|
+
|
|
18
|
+
tools: []
|
|
14
19
|
---
|
|
15
20
|
|
|
16
21
|
# Navigator — Planner
|
|
@@ -4,13 +4,18 @@ role: Deep Researcher
|
|
|
4
4
|
description: Find ground truth on any topic — competitors, standards, technologies, markets
|
|
5
5
|
version: 1.0.0
|
|
6
6
|
|
|
7
|
-
skills:
|
|
7
|
+
skills:
|
|
8
|
+
- deep-search
|
|
9
|
+
- source-verification
|
|
8
10
|
|
|
9
11
|
permissions:
|
|
10
12
|
can-read: true
|
|
11
13
|
can-execute: false
|
|
12
14
|
can-plan: false
|
|
13
15
|
can-approve: false
|
|
16
|
+
approval-required: []
|
|
17
|
+
|
|
18
|
+
tools: []
|
|
14
19
|
---
|
|
15
20
|
|
|
16
21
|
# Researcher — Deep Researcher
|
|
@@ -4,7 +4,9 @@ role: Reviewer
|
|
|
4
4
|
description: Validate execution, run tests, ensure quality before shipping
|
|
5
5
|
version: 1.0.0
|
|
6
6
|
|
|
7
|
-
skills:
|
|
7
|
+
skills:
|
|
8
|
+
- test-runner
|
|
9
|
+
- doc-updater
|
|
8
10
|
|
|
9
11
|
permissions:
|
|
10
12
|
can-read: true
|
|
@@ -12,6 +14,9 @@ permissions:
|
|
|
12
14
|
can-execute: false
|
|
13
15
|
can-approve: true
|
|
14
16
|
can-ship: true
|
|
17
|
+
approval-required: []
|
|
18
|
+
|
|
19
|
+
tools: []
|
|
15
20
|
---
|
|
16
21
|
|
|
17
22
|
# Validator — Reviewer
|
package/commands/init.js
CHANGED
|
@@ -475,24 +475,53 @@ function initAtris() {
|
|
|
475
475
|
});
|
|
476
476
|
|
|
477
477
|
|
|
478
|
-
// Copy team members (MEMBER.md format — directory per member)
|
|
479
|
-
const members = ['navigator', 'executor', 'validator', 'launcher', 'brainstormer'];
|
|
478
|
+
// Copy team members (MEMBER.md format — directory per member with skills/tools/context)
|
|
479
|
+
const members = ['navigator', 'executor', 'validator', 'launcher', 'brainstormer', 'researcher'];
|
|
480
480
|
members.forEach(name => {
|
|
481
481
|
const sourceFile = path.join(__dirname, '..', 'atris', 'team', name, 'MEMBER.md');
|
|
482
|
-
const
|
|
483
|
-
const targetFile = path.join(
|
|
482
|
+
const targetMemberDir = path.join(teamDir, name);
|
|
483
|
+
const targetFile = path.join(targetMemberDir, 'MEMBER.md');
|
|
484
484
|
const legacyFile = path.join(teamDir, `${name}.md`);
|
|
485
485
|
|
|
486
486
|
// Skip if already exists (either format)
|
|
487
487
|
if (fs.existsSync(targetFile) || fs.existsSync(legacyFile)) return;
|
|
488
488
|
|
|
489
489
|
if (fs.existsSync(sourceFile)) {
|
|
490
|
-
fs.mkdirSync(
|
|
490
|
+
fs.mkdirSync(targetMemberDir, { recursive: true });
|
|
491
|
+
fs.mkdirSync(path.join(targetMemberDir, 'skills'), { recursive: true });
|
|
492
|
+
fs.mkdirSync(path.join(targetMemberDir, 'tools'), { recursive: true });
|
|
493
|
+
fs.mkdirSync(path.join(targetMemberDir, 'context'), { recursive: true });
|
|
491
494
|
fs.copyFileSync(sourceFile, targetFile);
|
|
492
|
-
console.log(`✓ Created team/${name}/MEMBER.md`);
|
|
495
|
+
console.log(`✓ Created team/${name}/ (MEMBER.md + skills/ + tools/ + context/)`);
|
|
493
496
|
}
|
|
494
497
|
});
|
|
495
498
|
|
|
499
|
+
// Copy MEMBER.md template for creating custom members
|
|
500
|
+
const templateSourceDir = path.join(__dirname, '..', 'atris', 'team', '_template');
|
|
501
|
+
const templateTargetDir = path.join(teamDir, '_template');
|
|
502
|
+
if (!fs.existsSync(templateTargetDir)) {
|
|
503
|
+
fs.mkdirSync(templateTargetDir, { recursive: true });
|
|
504
|
+
const templateContent = `---
|
|
505
|
+
name: template-member
|
|
506
|
+
role: Replace with role title
|
|
507
|
+
description: Replace with one-line description of what this member does.
|
|
508
|
+
version: 1.0.0
|
|
509
|
+
|
|
510
|
+
skills: []
|
|
511
|
+
|
|
512
|
+
permissions:
|
|
513
|
+
can-read: true
|
|
514
|
+
approval-required: []
|
|
515
|
+
|
|
516
|
+
tools: []
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
# Insert persona, workflow, and rules below
|
|
520
|
+
`;
|
|
521
|
+
fs.writeFileSync(path.join(templateTargetDir, 'MEMBER.md'), templateContent);
|
|
522
|
+
console.log('✓ Created team/_template/MEMBER.md');
|
|
523
|
+
}
|
|
524
|
+
|
|
496
525
|
// Detect project context and generate profile
|
|
497
526
|
const profile = detectProjectContext(process.cwd());
|
|
498
527
|
const profileFile = path.join(targetDir, '.project-profile.json');
|
package/commands/member.js
CHANGED
package/package.json
CHANGED