@vibe-agent-toolkit/vat-development-agents 0.1.22-rc.2 → 0.1.22
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/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/.claude-plugin/plugin.json +1 -0
- package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/org-admin/SKILL.md +337 -0
- package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vibe-agent-toolkit/SKILL.md +1 -0
- package/dist/generated/resources/skills/SKILL.js +3 -3
- package/dist/generated/resources/skills/vat-claude-org-admin.d.ts +27 -0
- package/dist/generated/resources/skills/vat-claude-org-admin.js +43 -0
- package/dist/skills/org-admin/SKILL.md +337 -0
- package/dist/skills/vibe-agent-toolkit/SKILL.md +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: org-admin
|
|
3
|
+
description: Anthropic org administration for Enterprise/Team admins. Requires ANTHROPIC_ADMIN_API_KEY. Use for org user management, API key auditing, cost/usage reporting, workspace administration, and enterprise skill distribution via the Anthropic Admin API. Not for regular users — admin access required.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Claude Org Administration
|
|
7
|
+
|
|
8
|
+
**For Anthropic org admins only.** Requires `ANTHROPIC_ADMIN_API_KEY` (Enterprise/Team plan).
|
|
9
|
+
If you don't have an admin key, this skill is not for you — use `vibe-agent-toolkit:distribution`
|
|
10
|
+
for local plugin management instead.
|
|
11
|
+
|
|
12
|
+
## Two Ways to Use It
|
|
13
|
+
|
|
14
|
+
### CLI — Quick Queries
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
vat claude org info # Org identity
|
|
18
|
+
vat claude org users list # All members
|
|
19
|
+
vat claude org api-keys list --status active # Active API keys
|
|
20
|
+
vat claude org cost --group-by description # Cost breakdown by model
|
|
21
|
+
vat claude org usage --from 2025-01-01T00:00:00Z # Token usage since Jan
|
|
22
|
+
vat claude org skills list # Workspace-scoped skills (requires ANTHROPIC_API_KEY)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Library — Scripts and Automation
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { OrgApiClient, createOrgApiClientFromEnv } from '@vibe-agent-toolkit/claude-marketplace';
|
|
29
|
+
|
|
30
|
+
// Reads ANTHROPIC_ADMIN_API_KEY and optionally ANTHROPIC_API_KEY from env
|
|
31
|
+
const client = createOrgApiClientFromEnv();
|
|
32
|
+
|
|
33
|
+
// Or construct directly
|
|
34
|
+
const client = new OrgApiClient({
|
|
35
|
+
adminApiKey: 'sk-ant-admin-...',
|
|
36
|
+
apiKey: 'sk-ant-api03-...', // only needed for skills endpoints
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## API Reference
|
|
41
|
+
|
|
42
|
+
### Auth: Two Keys, Two Surfaces
|
|
43
|
+
|
|
44
|
+
| Key | Env Var | Endpoints | Who Has It |
|
|
45
|
+
|---|---|---|---|
|
|
46
|
+
| Admin API key | `ANTHROPIC_ADMIN_API_KEY` | `/v1/organizations/*` | Org admins only |
|
|
47
|
+
| Regular API key | `ANTHROPIC_API_KEY` | `/v1/skills` (beta) | Any workspace member |
|
|
48
|
+
|
|
49
|
+
### Endpoints and Methods
|
|
50
|
+
|
|
51
|
+
**Org identity:**
|
|
52
|
+
```typescript
|
|
53
|
+
const org = await client.get<{ id: string; type: string; name: string }>('/v1/organizations/me');
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Users:**
|
|
57
|
+
```typescript
|
|
58
|
+
// List (paginated with limit/after_id)
|
|
59
|
+
const users = await client.get<{ data: OrgUser[]; has_more: boolean }>(
|
|
60
|
+
'/v1/organizations/users', { limit: 100 }
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
// Get single user
|
|
64
|
+
const user = await client.get<OrgUser>('/v1/organizations/users/user_abc123');
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Invites:**
|
|
68
|
+
```typescript
|
|
69
|
+
const invites = await client.get<{ data: OrgInvite[]; has_more: boolean }>(
|
|
70
|
+
'/v1/organizations/invites'
|
|
71
|
+
);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Workspaces:**
|
|
75
|
+
```typescript
|
|
76
|
+
const workspaces = await client.get<{ data: OrgWorkspace[]; has_more: boolean }>(
|
|
77
|
+
'/v1/organizations/workspaces'
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Workspace members
|
|
81
|
+
const members = await client.get<{ data: WorkspaceMember[]; has_more: boolean }>(
|
|
82
|
+
'/v1/organizations/workspaces/ws_abc/members'
|
|
83
|
+
);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**API keys:**
|
|
87
|
+
```typescript
|
|
88
|
+
const keys = await client.get<{ data: ApiKey[]; has_more: boolean }>(
|
|
89
|
+
'/v1/organizations/api_keys',
|
|
90
|
+
{ status: 'active', workspace_id: 'ws_abc' } // both filters optional
|
|
91
|
+
);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Skills (beta — uses regular API key):**
|
|
95
|
+
```typescript
|
|
96
|
+
// List skills
|
|
97
|
+
const skills = await client.getSkills<{ data: Skill[]; has_more: boolean }>('/v1/skills');
|
|
98
|
+
// Adds anthropic-beta: skills-2025-10-02 header automatically
|
|
99
|
+
|
|
100
|
+
// Upload a skill (multipart/form-data)
|
|
101
|
+
import { buildMultipartFormData } from '@vibe-agent-toolkit/claude-marketplace';
|
|
102
|
+
const multipart = buildMultipartFormData(
|
|
103
|
+
{ display_title: 'My Skill' },
|
|
104
|
+
[{ fieldName: 'files[]', filename: 'SKILL.md', content: Buffer.from(skillContent) }],
|
|
105
|
+
);
|
|
106
|
+
const created = await client.uploadSkill<{ id: string; latest_version: string }>(multipart);
|
|
107
|
+
|
|
108
|
+
// Delete a skill
|
|
109
|
+
const deleted = await client.deleteSkill<{ id: string; type: string }>(skillId);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Report Endpoints — Pagination Quirk
|
|
113
|
+
|
|
114
|
+
Usage, cost, and code-analytics endpoints have a **non-standard pagination model**.
|
|
115
|
+
They return `has_more: true` with a `next_page` cursor, but the API **rejects `next_page`
|
|
116
|
+
as a query parameter**. Paginate by advancing `starting_at` to the last bucket's `ending_at`.
|
|
117
|
+
|
|
118
|
+
**Usage report (daily token buckets):**
|
|
119
|
+
```typescript
|
|
120
|
+
interface UsageBucket {
|
|
121
|
+
starting_at: string;
|
|
122
|
+
ending_at: string;
|
|
123
|
+
results: Array<{
|
|
124
|
+
uncached_input_tokens: number;
|
|
125
|
+
cache_read_input_tokens: number;
|
|
126
|
+
output_tokens: number;
|
|
127
|
+
model: string | null;
|
|
128
|
+
workspace_id: string | null;
|
|
129
|
+
api_key_id: string | null;
|
|
130
|
+
service_tier: string | null;
|
|
131
|
+
// ... other dimension fields, null if not applicable
|
|
132
|
+
}>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// First page
|
|
136
|
+
let resp = await client.get<{ data: UsageBucket[]; has_more: boolean }>(
|
|
137
|
+
'/v1/organizations/usage_report/messages',
|
|
138
|
+
{ starting_at: '2025-01-01T00:00:00Z', ending_at: '2025-12-31T23:59:59Z' }
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// Subsequent pages — advance starting_at, do NOT pass next_page
|
|
142
|
+
const lastBucket = resp.data.at(-1);
|
|
143
|
+
resp = await client.get<{ data: UsageBucket[]; has_more: boolean }>(
|
|
144
|
+
'/v1/organizations/usage_report/messages',
|
|
145
|
+
{ starting_at: lastBucket.ending_at, ending_at: '2025-12-31T23:59:59Z' }
|
|
146
|
+
);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Cost report:**
|
|
150
|
+
```typescript
|
|
151
|
+
// amount is a STRING, not a number — parse before arithmetic
|
|
152
|
+
interface CostResult {
|
|
153
|
+
currency: string;
|
|
154
|
+
amount: string; // "7.0812" — use parseFloat()
|
|
155
|
+
description: string | null;
|
|
156
|
+
model: string | null;
|
|
157
|
+
token_type: string | null;
|
|
158
|
+
// ...
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// group_by[] needs URLSearchParams for repeated params
|
|
162
|
+
const qs = new URLSearchParams();
|
|
163
|
+
qs.set('starting_at', '2025-03-01T00:00:00Z');
|
|
164
|
+
qs.set('ending_at', '2025-03-31T23:59:59Z');
|
|
165
|
+
qs.append('group_by[]', 'description');
|
|
166
|
+
qs.append('group_by[]', 'workspace_id');
|
|
167
|
+
const resp = await client.get<{ data: CostBucket[] }>(
|
|
168
|
+
`/v1/organizations/cost_report?${qs.toString()}`
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// Sum costs
|
|
172
|
+
const total = resp.data
|
|
173
|
+
.flatMap(b => b.results)
|
|
174
|
+
.reduce((sum, r) => sum + parseFloat(r.amount), 0);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Code analytics (Claude Code productivity):**
|
|
178
|
+
```typescript
|
|
179
|
+
// Date-only format YYYY-MM-DD. No ending_at parameter.
|
|
180
|
+
const resp = await client.get<{ data: unknown[] }>(
|
|
181
|
+
'/v1/organizations/usage_report/claude_code',
|
|
182
|
+
{ starting_at: '2025-03-01' } // NOT ISO datetime
|
|
183
|
+
);
|
|
184
|
+
// Returns empty data[] when no Claude Code enterprise seats are active
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Common Recipes
|
|
188
|
+
|
|
189
|
+
### Monthly cost summary script
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import { createOrgApiClientFromEnv } from '@vibe-agent-toolkit/claude-marketplace';
|
|
193
|
+
|
|
194
|
+
const client = createOrgApiClientFromEnv();
|
|
195
|
+
const qs = new URLSearchParams();
|
|
196
|
+
qs.set('starting_at', '2025-03-01T00:00:00Z');
|
|
197
|
+
qs.set('ending_at', '2025-04-01T00:00:00Z');
|
|
198
|
+
qs.append('group_by[]', 'description');
|
|
199
|
+
|
|
200
|
+
const allResults = [];
|
|
201
|
+
let startingAt = '2025-03-01T00:00:00Z';
|
|
202
|
+
let hasMore = true;
|
|
203
|
+
|
|
204
|
+
while (hasMore) {
|
|
205
|
+
qs.set('starting_at', startingAt);
|
|
206
|
+
const resp = await client.get(`/v1/organizations/cost_report?${qs.toString()}`);
|
|
207
|
+
allResults.push(...resp.data);
|
|
208
|
+
const last = resp.data.at(-1);
|
|
209
|
+
hasMore = resp.has_more && last;
|
|
210
|
+
if (last) startingAt = last.ending_at;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const byDescription = new Map();
|
|
214
|
+
for (const bucket of allResults) {
|
|
215
|
+
for (const r of bucket.results) {
|
|
216
|
+
const key = r.description ?? 'unclassified';
|
|
217
|
+
byDescription.set(key, (byDescription.get(key) ?? 0) + parseFloat(r.amount));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
for (const [desc, total] of byDescription) {
|
|
221
|
+
console.log(`${desc}: $${total.toFixed(2)}`);
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### API key security audit
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
const client = createOrgApiClientFromEnv();
|
|
229
|
+
const { data: keys } = await client.get('/v1/organizations/api_keys', { limit: 100 });
|
|
230
|
+
|
|
231
|
+
const issues = [];
|
|
232
|
+
for (const key of keys) {
|
|
233
|
+
if (key.status === 'active' && !key.expires_at) {
|
|
234
|
+
issues.push(`${key.name}: active with no expiry`);
|
|
235
|
+
}
|
|
236
|
+
if (key.status === 'active' && !key.workspace_id) {
|
|
237
|
+
issues.push(`${key.name}: not scoped to a workspace`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
console.log(issues.length ? issues.join('\n') : 'All keys look good');
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### List org users who haven't accepted invites
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
const client = createOrgApiClientFromEnv();
|
|
247
|
+
const { data: invites } = await client.get('/v1/organizations/invites');
|
|
248
|
+
const pending = invites.filter(i => i.status !== 'accepted');
|
|
249
|
+
console.log(`${pending.length} pending invites:`, pending.map(i => i.email));
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## CLI Reference
|
|
253
|
+
|
|
254
|
+
All commands require `ANTHROPIC_ADMIN_API_KEY` unless noted.
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
vat claude org info Org identity (id, name)
|
|
258
|
+
vat claude org users list [--limit N] List members
|
|
259
|
+
vat claude org users get <user-id> Get single member
|
|
260
|
+
vat claude org invites list List invitations
|
|
261
|
+
vat claude org workspaces list List API workspaces
|
|
262
|
+
vat claude org workspaces get <id> Get single workspace
|
|
263
|
+
vat claude org workspaces members list <id> Workspace members
|
|
264
|
+
vat claude org api-keys list [--status S] API key inventory
|
|
265
|
+
vat claude org usage [--from DT] [--to DT] Token usage report
|
|
266
|
+
vat claude org cost [--from DT] [--group-by F] USD cost report
|
|
267
|
+
vat claude org code-analytics [--from DATE] Claude Code metrics (YYYY-MM-DD)
|
|
268
|
+
vat claude org skills list Workspace skills (needs ANTHROPIC_API_KEY)
|
|
269
|
+
vat claude org skills install <source> Upload skill dir or ZIP to org
|
|
270
|
+
vat claude org skills delete <skill-id> Delete a skill (versions first)
|
|
271
|
+
vat claude org skills versions list <skill-id> List skill versions
|
|
272
|
+
vat claude org skills versions delete <id> <ver> Delete a skill version
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Exit codes: `0` success, `1` expected failure (stubs), `2` system error (missing key, API error).
|
|
276
|
+
|
|
277
|
+
**Skill deletion lifecycle:** The API requires all versions to be deleted before the skill itself.
|
|
278
|
+
Use `versions list` to find versions, `versions delete` each one, then `delete` the skill.
|
|
279
|
+
|
|
280
|
+
## Enterprise Skill Distribution
|
|
281
|
+
|
|
282
|
+
### Skills API (claude.ai / Console)
|
|
283
|
+
|
|
284
|
+
Skills uploaded via `POST /v1/skills` are **workspace-scoped** and **automatically available to
|
|
285
|
+
all workspace members**. There is no per-user enable/disable via the API — visibility is
|
|
286
|
+
workspace-level only. The admin UI may have additional controls not exposed in the API.
|
|
287
|
+
|
|
288
|
+
**Upload from npm package:**
|
|
289
|
+
```bash
|
|
290
|
+
# Upload all skills from a package
|
|
291
|
+
vat claude org skills install --from-npm @scope/my-skills-package@1.0.0
|
|
292
|
+
|
|
293
|
+
# Upload a single skill
|
|
294
|
+
vat claude org skills install --from-npm @scope/my-skills-package@1.0.0 --skill my-skill
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
The package must contain `dist/skills/<name>/SKILL.md` (produced by `vat skills build`).
|
|
298
|
+
If skills are in a sub-dependency, the command searches `node_modules/*/dist/skills/` too.
|
|
299
|
+
|
|
300
|
+
**Duplicate titles are rejected** — the API enforces unique `display_title` per workspace.
|
|
301
|
+
When uploading multiple skills, failures are non-fatal; partial results are reported.
|
|
302
|
+
|
|
303
|
+
### Managed Settings (Claude Code plugins)
|
|
304
|
+
|
|
305
|
+
For enterprise-wide Claude Code plugin deployment (not the Skills API), use managed settings
|
|
306
|
+
pushed via MDM (Jamf, Intune, SCCM, etc.):
|
|
307
|
+
|
|
308
|
+
| Platform | Path |
|
|
309
|
+
|---|---|
|
|
310
|
+
| macOS | `/Library/Application Support/ClaudeCode/managed-settings.json` |
|
|
311
|
+
| Linux | `/etc/claude-code/managed-settings.json` |
|
|
312
|
+
| Windows | `C:\Program Files\ClaudeCode\managed-settings.json` |
|
|
313
|
+
|
|
314
|
+
Managed settings are **highest priority** in the settings cascade — they override user settings.
|
|
315
|
+
Use this to force-enable plugins, lock down permissions, or configure organization defaults.
|
|
316
|
+
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"enabledPlugins": {
|
|
320
|
+
"my-plugin@my-marketplace": true
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Combine with `npm install -g <package>` (via IT software deployment) to install the plugin
|
|
326
|
+
binary, then managed settings to enable it across all machines.
|
|
327
|
+
|
|
328
|
+
## Not Yet Implemented
|
|
329
|
+
|
|
330
|
+
These commands exist with the correct CLI shape but return structured
|
|
331
|
+
`not-yet-implemented` stubs (exit 1). Coming in a future release:
|
|
332
|
+
|
|
333
|
+
- `org users update/remove` — role changes, offboarding
|
|
334
|
+
- `org invites create/delete` — programmatic invitations
|
|
335
|
+
- `org workspaces create/archive` — workspace lifecycle
|
|
336
|
+
- `org workspaces members add/update/remove` — workspace membership
|
|
337
|
+
- `org api-keys update` — rename keys
|
|
@@ -40,6 +40,7 @@ non-TypeScript/JavaScript projects, or cases where you need deep framework-speci
|
|
|
40
40
|
| `--target claude-web` ZIP format | `vibe-agent-toolkit:distribution` |
|
|
41
41
|
| Install/uninstall methods, enterprise deployment, Desktop vs CLI paths | `vibe-agent-toolkit:install` |
|
|
42
42
|
| `vat audit`, `--compat`, CI validation | `vibe-agent-toolkit:audit` |
|
|
43
|
+
| `vat claude org`, Admin API, org users/cost/usage/skills, ANTHROPIC_ADMIN_API_KEY | `vibe-agent-toolkit:org-admin` |
|
|
43
44
|
| VAT behaves unexpectedly, debugging VAT, testing local VAT changes, VAT_ROOT_DIR | `vibe-agent-toolkit:debugging` |
|
|
44
45
|
|
|
45
46
|
## Agent Archetypes (Quick Reference)
|
|
@@ -7,7 +7,7 @@ export const meta = {
|
|
|
7
7
|
description: "Use when building, adopting, or learning vibe-agent-toolkit (VAT). Covers agent creation, CLI commands (vat skills, vat resources, vat audit, vat rag), runtime adapters, skill packaging, and resource validation. Routes to specialized sub-skills."
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export const text = "\n# Vibe Agent Toolkit Skill\n\n**Vibe Agent Toolkit (VAT)** is a modular toolkit for building portable AI agents that work across\nmultiple LLM frameworks and deployment targets. Write your agent logic once as plain TypeScript,\nthen deploy it to Vercel AI SDK, LangChain, OpenAI, Claude Agent SDK, or any other runtime using\nframework adapters. No vendor lock-in.\n\n## Purpose: For Users, Not Contributors\n\n- **This skill** = How to USE VAT to build agents\n- **\`vibe-agent-toolkit:debugging\`** = When VAT itself behaves unexpectedly or you need to test a fix\n- **Root CLAUDE.md** = How to DEVELOP the VAT codebase itself\n\n## When to Use VAT\n\n**VAT is great for:** Multi-framework projects, reusable agent libraries, testing across LLM\nproviders, complex multi-agent orchestration, human-in-the-loop workflows.\n\n**VAT may not be needed for:** Simple one-off scripts where the framework is already decided,\nnon-TypeScript/JavaScript projects, or cases where you need deep framework-specific features.\n\n## Skill Routing Table\n\n| If you\'re working on... | Use this skill |\n|---|---|\n| Writing or structuring a \`SKILL.md\` file | \`vibe-agent-toolkit:authoring\` |\n| Agent archetypes, orchestration patterns, result envelopes | \`vibe-agent-toolkit:authoring\` |\n| \`packagingOptions\` (linkFollowDepth, excludeReferencesFromBundle) | \`vibe-agent-toolkit:authoring\` |\n| Resource collections, frontmatter schema validation | \`vibe-agent-toolkit:resources\` |\n| \`vat resources validate\`, collection config | \`vibe-agent-toolkit:resources\` |\n| Setting up \`vat build\` + \`vat claude build\` for a project | \`vibe-agent-toolkit:distribution\` |\n| Configuring \`claude:\` section in vibe-agent-toolkit.config.yaml | \`vibe-agent-toolkit:distribution\` |\n| npm publishing with plugin postinstall | \`vibe-agent-toolkit:distribution\` |\n| \`vat build\` / \`vat verify\` orchestration | \`vibe-agent-toolkit:distribution\` |\n| \`--target claude-web\` ZIP format | \`vibe-agent-toolkit:distribution\` |\n| Install/uninstall methods, enterprise deployment, Desktop vs CLI paths | \`vibe-agent-toolkit:install\` |\n| \`vat audit\`, \`--compat\`, CI validation | \`vibe-agent-toolkit:audit\` |\n| VAT behaves unexpectedly, debugging VAT, testing local VAT changes, VAT_ROOT_DIR | \`vibe-agent-toolkit:debugging\` |\n\n## Agent Archetypes (Quick Reference)\n\nFour patterns cover most use cases. For full code examples, see \`vibe-agent-toolkit:authoring\`.\n\n| Archetype | When to Use |\n|---|---|\n| **Pure Function Tool** | Stateless validation, transformation, computation — no LLM needed |\n| **One-Shot LLM Analyzer** | Single LLM call for analysis, classification, or generation |\n| **Conversational Assistant** | Multi-turn dialogue with session state across turns |\n| **External Event Integrator** | Waiting for human approval, webhooks, or third-party APIs |\n\n## Core CLI Commands\n\n\`\`\`bash\n# Install VAT CLI globally\nnpm install -g vibe-agent-toolkit\n\n# Top-level orchestration\nvat build # build all artifacts (skills then claude plugins)\nvat verify # verify all artifacts (resources, skills, claude)\n\n# Claude plugin commands\nvat claude build # generate plugin artifacts from built skills\nvat claude verify # validate plugin artifacts\n\n# Skills\nvat skills list # list skills in current project\nvat skills list --user # list user-installed skills\nvat skills install npm:@org/my-skills # install from npm (routes through plugin system)\nvat skills build # build portable skills only\nvat skills validate # validate skill quality\n\n# Resources\nvat resources validate # validate collections (reads config)\nvat resources validate docs/ --frontmatter-schema schema.json\n\n# Audit\nvat audit # audit current directory recursively\nvat audit --user # audit entire Claude installation\nvat audit ./plugins/ --compat # check surface compatibility\n\n# RAG\nvat rag index docs/ # index markdown into vector DB\nvat rag query \"my question\" --limit 5 # semantic search\n\n# Get help for any command\nvat --help\nvat skills --help\n\`\`\`\n\n## agent-generator: Creating New Agents\n\nThe **agent-generator** is a built-in meta-agent that guides you through designing\nhigh-quality agents via a 4-phase workflow:\n\n1. **GATHER** — Understand your intent and goals\n2. **ANALYZE** — Identify agent pattern and requirements\n3. **DESIGN** — Make architecture decisions (LLM, tools, prompts)\n4. **GENERATE** — Create validated agent package\n\nMinimum input needed:\n\`\`\`json\n{\n \"agentPurpose\": \"Review PRs for security issues\",\n \"successCriteria\": \"Catches 100% of critical vulnerabilities\"\n}\n\`\`\`\n\nThe generator produces: \`agent.yaml\`, \`prompts/system.md\`, \`prompts/user.md\`,\n\`schemas/input.schema.json\`, \`schemas/output.schema.json\`, and \`README.md\`.\n\n**Tips for better results:**\n- Be specific about success criteria (\"Under 30s, zero false negatives\") not vague (\"fast enough\")\n- Name the tools the agent needs upfront (file readers, APIs, etc.)\n- Describe domain context (OWASP Top 10, company coding standards, etc.)\n\n## Packaging Markdown for Reuse\n\nVAT\'s resource compiler transforms markdown files into type-safe TypeScript modules,\nenabling prompt libraries, RAG knowledge bases, and shared content across projects.\n\n\`\`\`bash\nnpm install -D @vibe-agent-toolkit/resource-compiler\nnpx vat-compile-resources compile resources/ generated/resources/\n\`\`\`\n\n\`\`\`typescript\nimport * as Doc from \'./generated/resources/doc.js\';\n\nDoc.meta.title; // type-safe frontmatter\nDoc.fragments.introduction.text; // H2 section content\nDoc.text; // full markdown\n\`\`\`\n\nUse cases: agent prompt libraries, RAG knowledge bases packaged as npm modules,\nmulti-project content sharing with versioning.\n\n## Common Workflows\n\n**Create a new agent:**\n\`\`\`bash\n# Use agent-generator interactively, then:\nvat agent import my-skill/SKILL.md # import to VAT format\nvat skills validate # check quality\nvat skills build # package for distribution\n\`\`\`\n\n**Install and use a community skill:**\n\`\`\`bash\nvat skills install npm:@vibe-agent-toolkit/vat-cat-agents\nvat skills list --user\n# Plugin-aware packages register in Claude\'s plugin system\n# Skills are invoked as /plugin-name:skill-name in Claude Code\n\`\`\`\n\n**Build and publish your own skill package:**\n\`\`\`bash\n# Configure vat.skills in package.json + claude: in vibe-agent-toolkit.config.yaml, then:\nvat build # builds skills + claude plugin artifacts\nvat verify # validates everything\nnpm publish # publishes to npm (postinstall registers the plugin)\n# Users install with: vat skills install npm:@myorg/my-skills\n\`\`\`\n\n## Success Criteria\n\nYou\'ve successfully adopted VAT when:\n- Agents have clear input/output schemas (Zod-validated)\n- Errors are handled as data (result envelopes), never thrown\n- Tests cover success and error paths without real API calls (mock mode)\n- Agents work across multiple runtimes via adapters\n- Multi-agent pipelines compose via \`andThen()\` / \`match()\` helpers\n\n## Documentation Index\n\n- [Getting Started Guide](../../../../docs/getting-started.md)\n- [Agent Authoring Guide](../../../../docs/agent-authoring.md) — patterns and code examples\n- [Orchestration Guide](../../../../docs/orchestration.md) — multi-agent workflows\n- [RAG Usage Guide](../../../../docs/guides/rag-usage-guide.md)\n- [Resource Compiler Guide](../../../../docs/guides/resource-compiler/compiling-markdown-to-typescript.md)\n- [Runtime Adapters](../../../../docs/adding-runtime-adapters.md)\n- Examples: \`@vibe-agent-toolkit/vat-example-cat-agents\`\n\n## Getting Help\n\n- **CLI Help:** \`vat --help\`, \`vat skills --help\`, etc.\n- **Examples:** \`packages/vat-example-cat-agents/\`\n- **GitHub Issues:** Report bugs or ask questions\n\nHappy agent building!\n";
|
|
10
|
+
export const text = "\n# Vibe Agent Toolkit Skill\n\n**Vibe Agent Toolkit (VAT)** is a modular toolkit for building portable AI agents that work across\nmultiple LLM frameworks and deployment targets. Write your agent logic once as plain TypeScript,\nthen deploy it to Vercel AI SDK, LangChain, OpenAI, Claude Agent SDK, or any other runtime using\nframework adapters. No vendor lock-in.\n\n## Purpose: For Users, Not Contributors\n\n- **This skill** = How to USE VAT to build agents\n- **\`vibe-agent-toolkit:debugging\`** = When VAT itself behaves unexpectedly or you need to test a fix\n- **Root CLAUDE.md** = How to DEVELOP the VAT codebase itself\n\n## When to Use VAT\n\n**VAT is great for:** Multi-framework projects, reusable agent libraries, testing across LLM\nproviders, complex multi-agent orchestration, human-in-the-loop workflows.\n\n**VAT may not be needed for:** Simple one-off scripts where the framework is already decided,\nnon-TypeScript/JavaScript projects, or cases where you need deep framework-specific features.\n\n## Skill Routing Table\n\n| If you\'re working on... | Use this skill |\n|---|---|\n| Writing or structuring a \`SKILL.md\` file | \`vibe-agent-toolkit:authoring\` |\n| Agent archetypes, orchestration patterns, result envelopes | \`vibe-agent-toolkit:authoring\` |\n| \`packagingOptions\` (linkFollowDepth, excludeReferencesFromBundle) | \`vibe-agent-toolkit:authoring\` |\n| Resource collections, frontmatter schema validation | \`vibe-agent-toolkit:resources\` |\n| \`vat resources validate\`, collection config | \`vibe-agent-toolkit:resources\` |\n| Setting up \`vat build\` + \`vat claude build\` for a project | \`vibe-agent-toolkit:distribution\` |\n| Configuring \`claude:\` section in vibe-agent-toolkit.config.yaml | \`vibe-agent-toolkit:distribution\` |\n| npm publishing with plugin postinstall | \`vibe-agent-toolkit:distribution\` |\n| \`vat build\` / \`vat verify\` orchestration | \`vibe-agent-toolkit:distribution\` |\n| \`--target claude-web\` ZIP format | \`vibe-agent-toolkit:distribution\` |\n| Install/uninstall methods, enterprise deployment, Desktop vs CLI paths | \`vibe-agent-toolkit:install\` |\n| \`vat audit\`, \`--compat\`, CI validation | \`vibe-agent-toolkit:audit\` |\n| \`vat claude org\`, Admin API, org users/cost/usage/skills, ANTHROPIC_ADMIN_API_KEY | \`vibe-agent-toolkit:org-admin\` |\n| VAT behaves unexpectedly, debugging VAT, testing local VAT changes, VAT_ROOT_DIR | \`vibe-agent-toolkit:debugging\` |\n\n## Agent Archetypes (Quick Reference)\n\nFour patterns cover most use cases. For full code examples, see \`vibe-agent-toolkit:authoring\`.\n\n| Archetype | When to Use |\n|---|---|\n| **Pure Function Tool** | Stateless validation, transformation, computation — no LLM needed |\n| **One-Shot LLM Analyzer** | Single LLM call for analysis, classification, or generation |\n| **Conversational Assistant** | Multi-turn dialogue with session state across turns |\n| **External Event Integrator** | Waiting for human approval, webhooks, or third-party APIs |\n\n## Core CLI Commands\n\n\`\`\`bash\n# Install VAT CLI globally\nnpm install -g vibe-agent-toolkit\n\n# Top-level orchestration\nvat build # build all artifacts (skills then claude plugins)\nvat verify # verify all artifacts (resources, skills, claude)\n\n# Claude plugin commands\nvat claude build # generate plugin artifacts from built skills\nvat claude verify # validate plugin artifacts\n\n# Skills\nvat skills list # list skills in current project\nvat skills list --user # list user-installed skills\nvat skills install npm:@org/my-skills # install from npm (routes through plugin system)\nvat skills build # build portable skills only\nvat skills validate # validate skill quality\n\n# Resources\nvat resources validate # validate collections (reads config)\nvat resources validate docs/ --frontmatter-schema schema.json\n\n# Audit\nvat audit # audit current directory recursively\nvat audit --user # audit entire Claude installation\nvat audit ./plugins/ --compat # check surface compatibility\n\n# RAG\nvat rag index docs/ # index markdown into vector DB\nvat rag query \"my question\" --limit 5 # semantic search\n\n# Get help for any command\nvat --help\nvat skills --help\n\`\`\`\n\n## agent-generator: Creating New Agents\n\nThe **agent-generator** is a built-in meta-agent that guides you through designing\nhigh-quality agents via a 4-phase workflow:\n\n1. **GATHER** — Understand your intent and goals\n2. **ANALYZE** — Identify agent pattern and requirements\n3. **DESIGN** — Make architecture decisions (LLM, tools, prompts)\n4. **GENERATE** — Create validated agent package\n\nMinimum input needed:\n\`\`\`json\n{\n \"agentPurpose\": \"Review PRs for security issues\",\n \"successCriteria\": \"Catches 100% of critical vulnerabilities\"\n}\n\`\`\`\n\nThe generator produces: \`agent.yaml\`, \`prompts/system.md\`, \`prompts/user.md\`,\n\`schemas/input.schema.json\`, \`schemas/output.schema.json\`, and \`README.md\`.\n\n**Tips for better results:**\n- Be specific about success criteria (\"Under 30s, zero false negatives\") not vague (\"fast enough\")\n- Name the tools the agent needs upfront (file readers, APIs, etc.)\n- Describe domain context (OWASP Top 10, company coding standards, etc.)\n\n## Packaging Markdown for Reuse\n\nVAT\'s resource compiler transforms markdown files into type-safe TypeScript modules,\nenabling prompt libraries, RAG knowledge bases, and shared content across projects.\n\n\`\`\`bash\nnpm install -D @vibe-agent-toolkit/resource-compiler\nnpx vat-compile-resources compile resources/ generated/resources/\n\`\`\`\n\n\`\`\`typescript\nimport * as Doc from \'./generated/resources/doc.js\';\n\nDoc.meta.title; // type-safe frontmatter\nDoc.fragments.introduction.text; // H2 section content\nDoc.text; // full markdown\n\`\`\`\n\nUse cases: agent prompt libraries, RAG knowledge bases packaged as npm modules,\nmulti-project content sharing with versioning.\n\n## Common Workflows\n\n**Create a new agent:**\n\`\`\`bash\n# Use agent-generator interactively, then:\nvat agent import my-skill/SKILL.md # import to VAT format\nvat skills validate # check quality\nvat skills build # package for distribution\n\`\`\`\n\n**Install and use a community skill:**\n\`\`\`bash\nvat skills install npm:@vibe-agent-toolkit/vat-cat-agents\nvat skills list --user\n# Plugin-aware packages register in Claude\'s plugin system\n# Skills are invoked as /plugin-name:skill-name in Claude Code\n\`\`\`\n\n**Build and publish your own skill package:**\n\`\`\`bash\n# Configure vat.skills in package.json + claude: in vibe-agent-toolkit.config.yaml, then:\nvat build # builds skills + claude plugin artifacts\nvat verify # validates everything\nnpm publish # publishes to npm (postinstall registers the plugin)\n# Users install with: vat skills install npm:@myorg/my-skills\n\`\`\`\n\n## Success Criteria\n\nYou\'ve successfully adopted VAT when:\n- Agents have clear input/output schemas (Zod-validated)\n- Errors are handled as data (result envelopes), never thrown\n- Tests cover success and error paths without real API calls (mock mode)\n- Agents work across multiple runtimes via adapters\n- Multi-agent pipelines compose via \`andThen()\` / \`match()\` helpers\n\n## Documentation Index\n\n- [Getting Started Guide](../../../../docs/getting-started.md)\n- [Agent Authoring Guide](../../../../docs/agent-authoring.md) — patterns and code examples\n- [Orchestration Guide](../../../../docs/orchestration.md) — multi-agent workflows\n- [RAG Usage Guide](../../../../docs/guides/rag-usage-guide.md)\n- [Resource Compiler Guide](../../../../docs/guides/resource-compiler/compiling-markdown-to-typescript.md)\n- [Runtime Adapters](../../../../docs/adding-runtime-adapters.md)\n- Examples: \`@vibe-agent-toolkit/vat-example-cat-agents\`\n\n## Getting Help\n\n- **CLI Help:** \`vat --help\`, \`vat skills --help\`, etc.\n- **Examples:** \`packages/vat-example-cat-agents/\`\n- **GitHub Issues:** Report bugs or ask questions\n\nHappy agent building!\n";
|
|
11
11
|
|
|
12
12
|
export const fragments = {
|
|
13
13
|
purposeForUsersNotContributors: {
|
|
@@ -22,8 +22,8 @@ export const fragments = {
|
|
|
22
22
|
},
|
|
23
23
|
skillRoutingTable: {
|
|
24
24
|
header: "## Skill Routing Table",
|
|
25
|
-
body: "| If you\'re working on... | Use this skill |\n|---|---|\n| Writing or structuring a \`SKILL.md\` file | \`vibe-agent-toolkit:authoring\` |\n| Agent archetypes, orchestration patterns, result envelopes | \`vibe-agent-toolkit:authoring\` |\n| \`packagingOptions\` (linkFollowDepth, excludeReferencesFromBundle) | \`vibe-agent-toolkit:authoring\` |\n| Resource collections, frontmatter schema validation | \`vibe-agent-toolkit:resources\` |\n| \`vat resources validate\`, collection config | \`vibe-agent-toolkit:resources\` |\n| Setting up \`vat build\` + \`vat claude build\` for a project | \`vibe-agent-toolkit:distribution\` |\n| Configuring \`claude:\` section in vibe-agent-toolkit.config.yaml | \`vibe-agent-toolkit:distribution\` |\n| npm publishing with plugin postinstall | \`vibe-agent-toolkit:distribution\` |\n| \`vat build\` / \`vat verify\` orchestration | \`vibe-agent-toolkit:distribution\` |\n| \`--target claude-web\` ZIP format | \`vibe-agent-toolkit:distribution\` |\n| Install/uninstall methods, enterprise deployment, Desktop vs CLI paths | \`vibe-agent-toolkit:install\` |\n| \`vat audit\`, \`--compat\`, CI validation | \`vibe-agent-toolkit:audit\` |\n| VAT behaves unexpectedly, debugging VAT, testing local VAT changes, VAT_ROOT_DIR | \`vibe-agent-toolkit:debugging\` |",
|
|
26
|
-
text: "## Skill Routing Table\n\n| If you\'re working on... | Use this skill |\n|---|---|\n| Writing or structuring a \`SKILL.md\` file | \`vibe-agent-toolkit:authoring\` |\n| Agent archetypes, orchestration patterns, result envelopes | \`vibe-agent-toolkit:authoring\` |\n| \`packagingOptions\` (linkFollowDepth, excludeReferencesFromBundle) | \`vibe-agent-toolkit:authoring\` |\n| Resource collections, frontmatter schema validation | \`vibe-agent-toolkit:resources\` |\n| \`vat resources validate\`, collection config | \`vibe-agent-toolkit:resources\` |\n| Setting up \`vat build\` + \`vat claude build\` for a project | \`vibe-agent-toolkit:distribution\` |\n| Configuring \`claude:\` section in vibe-agent-toolkit.config.yaml | \`vibe-agent-toolkit:distribution\` |\n| npm publishing with plugin postinstall | \`vibe-agent-toolkit:distribution\` |\n| \`vat build\` / \`vat verify\` orchestration | \`vibe-agent-toolkit:distribution\` |\n| \`--target claude-web\` ZIP format | \`vibe-agent-toolkit:distribution\` |\n| Install/uninstall methods, enterprise deployment, Desktop vs CLI paths | \`vibe-agent-toolkit:install\` |\n| \`vat audit\`, \`--compat\`, CI validation | \`vibe-agent-toolkit:audit\` |\n| VAT behaves unexpectedly, debugging VAT, testing local VAT changes, VAT_ROOT_DIR | \`vibe-agent-toolkit:debugging\` |"
|
|
25
|
+
body: "| If you\'re working on... | Use this skill |\n|---|---|\n| Writing or structuring a \`SKILL.md\` file | \`vibe-agent-toolkit:authoring\` |\n| Agent archetypes, orchestration patterns, result envelopes | \`vibe-agent-toolkit:authoring\` |\n| \`packagingOptions\` (linkFollowDepth, excludeReferencesFromBundle) | \`vibe-agent-toolkit:authoring\` |\n| Resource collections, frontmatter schema validation | \`vibe-agent-toolkit:resources\` |\n| \`vat resources validate\`, collection config | \`vibe-agent-toolkit:resources\` |\n| Setting up \`vat build\` + \`vat claude build\` for a project | \`vibe-agent-toolkit:distribution\` |\n| Configuring \`claude:\` section in vibe-agent-toolkit.config.yaml | \`vibe-agent-toolkit:distribution\` |\n| npm publishing with plugin postinstall | \`vibe-agent-toolkit:distribution\` |\n| \`vat build\` / \`vat verify\` orchestration | \`vibe-agent-toolkit:distribution\` |\n| \`--target claude-web\` ZIP format | \`vibe-agent-toolkit:distribution\` |\n| Install/uninstall methods, enterprise deployment, Desktop vs CLI paths | \`vibe-agent-toolkit:install\` |\n| \`vat audit\`, \`--compat\`, CI validation | \`vibe-agent-toolkit:audit\` |\n| \`vat claude org\`, Admin API, org users/cost/usage/skills, ANTHROPIC_ADMIN_API_KEY | \`vibe-agent-toolkit:org-admin\` |\n| VAT behaves unexpectedly, debugging VAT, testing local VAT changes, VAT_ROOT_DIR | \`vibe-agent-toolkit:debugging\` |",
|
|
26
|
+
text: "## Skill Routing Table\n\n| If you\'re working on... | Use this skill |\n|---|---|\n| Writing or structuring a \`SKILL.md\` file | \`vibe-agent-toolkit:authoring\` |\n| Agent archetypes, orchestration patterns, result envelopes | \`vibe-agent-toolkit:authoring\` |\n| \`packagingOptions\` (linkFollowDepth, excludeReferencesFromBundle) | \`vibe-agent-toolkit:authoring\` |\n| Resource collections, frontmatter schema validation | \`vibe-agent-toolkit:resources\` |\n| \`vat resources validate\`, collection config | \`vibe-agent-toolkit:resources\` |\n| Setting up \`vat build\` + \`vat claude build\` for a project | \`vibe-agent-toolkit:distribution\` |\n| Configuring \`claude:\` section in vibe-agent-toolkit.config.yaml | \`vibe-agent-toolkit:distribution\` |\n| npm publishing with plugin postinstall | \`vibe-agent-toolkit:distribution\` |\n| \`vat build\` / \`vat verify\` orchestration | \`vibe-agent-toolkit:distribution\` |\n| \`--target claude-web\` ZIP format | \`vibe-agent-toolkit:distribution\` |\n| Install/uninstall methods, enterprise deployment, Desktop vs CLI paths | \`vibe-agent-toolkit:install\` |\n| \`vat audit\`, \`--compat\`, CI validation | \`vibe-agent-toolkit:audit\` |\n| \`vat claude org\`, Admin API, org users/cost/usage/skills, ANTHROPIC_ADMIN_API_KEY | \`vibe-agent-toolkit:org-admin\` |\n| VAT behaves unexpectedly, debugging VAT, testing local VAT changes, VAT_ROOT_DIR | \`vibe-agent-toolkit:debugging\` |"
|
|
27
27
|
},
|
|
28
28
|
agentArchetypesQuickReference: {
|
|
29
29
|
header: "## Agent Archetypes (Quick Reference)",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated TypeScript declarations - DO NOT EDIT
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface Fragment {
|
|
6
|
+
readonly header: string;
|
|
7
|
+
readonly body: string;
|
|
8
|
+
readonly text: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const meta: {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly description: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const text: string;
|
|
17
|
+
|
|
18
|
+
export const fragments: {
|
|
19
|
+
readonly twoWaysToUseIt: Fragment;
|
|
20
|
+
readonly apiReference: Fragment;
|
|
21
|
+
readonly commonRecipes: Fragment;
|
|
22
|
+
readonly cliReference: Fragment;
|
|
23
|
+
readonly enterpriseSkillDistribution: Fragment;
|
|
24
|
+
readonly notYetImplemented: Fragment;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type FragmentName = keyof typeof fragments;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated from markdown file - DO NOT EDIT
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const meta = {
|
|
6
|
+
name: "org-admin",
|
|
7
|
+
description: "Anthropic org administration for Enterprise/Team admins. Requires ANTHROPIC_ADMIN_API_KEY. Use for org user management, API key auditing, cost/usage reporting, workspace administration, and enterprise skill distribution via the Anthropic Admin API. Not for regular users — admin access required."
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const text = "\n# Claude Org Administration\n\n**For Anthropic org admins only.** Requires \`ANTHROPIC_ADMIN_API_KEY\` (Enterprise/Team plan).\nIf you don\'t have an admin key, this skill is not for you — use \`vibe-agent-toolkit:distribution\`\nfor local plugin management instead.\n\n## Two Ways to Use It\n\n### CLI — Quick Queries\n\n\`\`\`bash\nvat claude org info # Org identity\nvat claude org users list # All members\nvat claude org api-keys list --status active # Active API keys\nvat claude org cost --group-by description # Cost breakdown by model\nvat claude org usage --from 2025-01-01T00:00:00Z # Token usage since Jan\nvat claude org skills list # Workspace-scoped skills (requires ANTHROPIC_API_KEY)\n\`\`\`\n\n### Library — Scripts and Automation\n\n\`\`\`typescript\nimport { OrgApiClient, createOrgApiClientFromEnv } from \'@vibe-agent-toolkit/claude-marketplace\';\n\n// Reads ANTHROPIC_ADMIN_API_KEY and optionally ANTHROPIC_API_KEY from env\nconst client = createOrgApiClientFromEnv();\n\n// Or construct directly\nconst client = new OrgApiClient({\n adminApiKey: \'sk-ant-admin-...\',\n apiKey: \'sk-ant-api03-...\', // only needed for skills endpoints\n});\n\`\`\`\n\n## API Reference\n\n### Auth: Two Keys, Two Surfaces\n\n| Key | Env Var | Endpoints | Who Has It |\n|---|---|---|---|\n| Admin API key | \`ANTHROPIC_ADMIN_API_KEY\` | \`/v1/organizations/*\` | Org admins only |\n| Regular API key | \`ANTHROPIC_API_KEY\` | \`/v1/skills\` (beta) | Any workspace member |\n\n### Endpoints and Methods\n\n**Org identity:**\n\`\`\`typescript\nconst org = await client.get<{ id: string; type: string; name: string }>(\'/v1/organizations/me\');\n\`\`\`\n\n**Users:**\n\`\`\`typescript\n// List (paginated with limit/after_id)\nconst users = await client.get<{ data: OrgUser[]; has_more: boolean }>(\n \'/v1/organizations/users\', { limit: 100 }\n);\n\n// Get single user\nconst user = await client.get<OrgUser>(\'/v1/organizations/users/user_abc123\');\n\`\`\`\n\n**Invites:**\n\`\`\`typescript\nconst invites = await client.get<{ data: OrgInvite[]; has_more: boolean }>(\n \'/v1/organizations/invites\'\n);\n\`\`\`\n\n**Workspaces:**\n\`\`\`typescript\nconst workspaces = await client.get<{ data: OrgWorkspace[]; has_more: boolean }>(\n \'/v1/organizations/workspaces\'\n);\n\n// Workspace members\nconst members = await client.get<{ data: WorkspaceMember[]; has_more: boolean }>(\n \'/v1/organizations/workspaces/ws_abc/members\'\n);\n\`\`\`\n\n**API keys:**\n\`\`\`typescript\nconst keys = await client.get<{ data: ApiKey[]; has_more: boolean }>(\n \'/v1/organizations/api_keys\',\n { status: \'active\', workspace_id: \'ws_abc\' } // both filters optional\n);\n\`\`\`\n\n**Skills (beta — uses regular API key):**\n\`\`\`typescript\n// List skills\nconst skills = await client.getSkills<{ data: Skill[]; has_more: boolean }>(\'/v1/skills\');\n// Adds anthropic-beta: skills-2025-10-02 header automatically\n\n// Upload a skill (multipart/form-data)\nimport { buildMultipartFormData } from \'@vibe-agent-toolkit/claude-marketplace\';\nconst multipart = buildMultipartFormData(\n { display_title: \'My Skill\' },\n [{ fieldName: \'files[]\', filename: \'SKILL.md\', content: Buffer.from(skillContent) }],\n);\nconst created = await client.uploadSkill<{ id: string; latest_version: string }>(multipart);\n\n// Delete a skill\nconst deleted = await client.deleteSkill<{ id: string; type: string }>(skillId);\n\`\`\`\n\n### Report Endpoints — Pagination Quirk\n\nUsage, cost, and code-analytics endpoints have a **non-standard pagination model**.\nThey return \`has_more: true\` with a \`next_page\` cursor, but the API **rejects \`next_page\`\nas a query parameter**. Paginate by advancing \`starting_at\` to the last bucket\'s \`ending_at\`.\n\n**Usage report (daily token buckets):**\n\`\`\`typescript\ninterface UsageBucket {\n starting_at: string;\n ending_at: string;\n results: Array<{\n uncached_input_tokens: number;\n cache_read_input_tokens: number;\n output_tokens: number;\n model: string | null;\n workspace_id: string | null;\n api_key_id: string | null;\n service_tier: string | null;\n // ... other dimension fields, null if not applicable\n }>;\n}\n\n// First page\nlet resp = await client.get<{ data: UsageBucket[]; has_more: boolean }>(\n \'/v1/organizations/usage_report/messages\',\n { starting_at: \'2025-01-01T00:00:00Z\', ending_at: \'2025-12-31T23:59:59Z\' }\n);\n\n// Subsequent pages — advance starting_at, do NOT pass next_page\nconst lastBucket = resp.data.at(-1);\nresp = await client.get<{ data: UsageBucket[]; has_more: boolean }>(\n \'/v1/organizations/usage_report/messages\',\n { starting_at: lastBucket.ending_at, ending_at: \'2025-12-31T23:59:59Z\' }\n);\n\`\`\`\n\n**Cost report:**\n\`\`\`typescript\n// amount is a STRING, not a number — parse before arithmetic\ninterface CostResult {\n currency: string;\n amount: string; // \"7.0812\" — use parseFloat()\n description: string | null;\n model: string | null;\n token_type: string | null;\n // ...\n}\n\n// group_by[] needs URLSearchParams for repeated params\nconst qs = new URLSearchParams();\nqs.set(\'starting_at\', \'2025-03-01T00:00:00Z\');\nqs.set(\'ending_at\', \'2025-03-31T23:59:59Z\');\nqs.append(\'group_by[]\', \'description\');\nqs.append(\'group_by[]\', \'workspace_id\');\nconst resp = await client.get<{ data: CostBucket[] }>(\n \`/v1/organizations/cost_report?${qs.toString()}\`\n);\n\n// Sum costs\nconst total = resp.data\n .flatMap(b => b.results)\n .reduce((sum, r) => sum + parseFloat(r.amount), 0);\n\`\`\`\n\n**Code analytics (Claude Code productivity):**\n\`\`\`typescript\n// Date-only format YYYY-MM-DD. No ending_at parameter.\nconst resp = await client.get<{ data: unknown[] }>(\n \'/v1/organizations/usage_report/claude_code\',\n { starting_at: \'2025-03-01\' } // NOT ISO datetime\n);\n// Returns empty data[] when no Claude Code enterprise seats are active\n\`\`\`\n\n## Common Recipes\n\n### Monthly cost summary script\n\n\`\`\`typescript\nimport { createOrgApiClientFromEnv } from \'@vibe-agent-toolkit/claude-marketplace\';\n\nconst client = createOrgApiClientFromEnv();\nconst qs = new URLSearchParams();\nqs.set(\'starting_at\', \'2025-03-01T00:00:00Z\');\nqs.set(\'ending_at\', \'2025-04-01T00:00:00Z\');\nqs.append(\'group_by[]\', \'description\');\n\nconst allResults = [];\nlet startingAt = \'2025-03-01T00:00:00Z\';\nlet hasMore = true;\n\nwhile (hasMore) {\n qs.set(\'starting_at\', startingAt);\n const resp = await client.get(\`/v1/organizations/cost_report?${qs.toString()}\`);\n allResults.push(...resp.data);\n const last = resp.data.at(-1);\n hasMore = resp.has_more && last;\n if (last) startingAt = last.ending_at;\n}\n\nconst byDescription = new Map();\nfor (const bucket of allResults) {\n for (const r of bucket.results) {\n const key = r.description ?? \'unclassified\';\n byDescription.set(key, (byDescription.get(key) ?? 0) + parseFloat(r.amount));\n }\n}\nfor (const [desc, total] of byDescription) {\n console.log(\`${desc}: $${total.toFixed(2)}\`);\n}\n\`\`\`\n\n### API key security audit\n\n\`\`\`typescript\nconst client = createOrgApiClientFromEnv();\nconst { data: keys } = await client.get(\'/v1/organizations/api_keys\', { limit: 100 });\n\nconst issues = [];\nfor (const key of keys) {\n if (key.status === \'active\' && !key.expires_at) {\n issues.push(\`${key.name}: active with no expiry\`);\n }\n if (key.status === \'active\' && !key.workspace_id) {\n issues.push(\`${key.name}: not scoped to a workspace\`);\n }\n}\nconsole.log(issues.length ? issues.join(\'\\n\') : \'All keys look good\');\n\`\`\`\n\n### List org users who haven\'t accepted invites\n\n\`\`\`typescript\nconst client = createOrgApiClientFromEnv();\nconst { data: invites } = await client.get(\'/v1/organizations/invites\');\nconst pending = invites.filter(i => i.status !== \'accepted\');\nconsole.log(\`${pending.length} pending invites:\`, pending.map(i => i.email));\n\`\`\`\n\n## CLI Reference\n\nAll commands require \`ANTHROPIC_ADMIN_API_KEY\` unless noted.\n\n\`\`\`\nvat claude org info Org identity (id, name)\nvat claude org users list [--limit N] List members\nvat claude org users get <user-id> Get single member\nvat claude org invites list List invitations\nvat claude org workspaces list List API workspaces\nvat claude org workspaces get <id> Get single workspace\nvat claude org workspaces members list <id> Workspace members\nvat claude org api-keys list [--status S] API key inventory\nvat claude org usage [--from DT] [--to DT] Token usage report\nvat claude org cost [--from DT] [--group-by F] USD cost report\nvat claude org code-analytics [--from DATE] Claude Code metrics (YYYY-MM-DD)\nvat claude org skills list Workspace skills (needs ANTHROPIC_API_KEY)\nvat claude org skills install <source> Upload skill dir or ZIP to org\nvat claude org skills delete <skill-id> Delete a skill (versions first)\nvat claude org skills versions list <skill-id> List skill versions\nvat claude org skills versions delete <id> <ver> Delete a skill version\n\`\`\`\n\nExit codes: \`0\` success, \`1\` expected failure (stubs), \`2\` system error (missing key, API error).\n\n**Skill deletion lifecycle:** The API requires all versions to be deleted before the skill itself.\nUse \`versions list\` to find versions, \`versions delete\` each one, then \`delete\` the skill.\n\n## Enterprise Skill Distribution\n\n### Skills API (claude.ai / Console)\n\nSkills uploaded via \`POST /v1/skills\` are **workspace-scoped** and **automatically available to\nall workspace members**. There is no per-user enable/disable via the API — visibility is\nworkspace-level only. The admin UI may have additional controls not exposed in the API.\n\n**Upload from npm package:**\n\`\`\`bash\n# Upload all skills from a package\nvat claude org skills install --from-npm @scope/my-skills-package@1.0.0\n\n# Upload a single skill\nvat claude org skills install --from-npm @scope/my-skills-package@1.0.0 --skill my-skill\n\`\`\`\n\nThe package must contain \`dist/skills/<name>/SKILL.md\` (produced by \`vat skills build\`).\nIf skills are in a sub-dependency, the command searches \`node_modules/*/dist/skills/\` too.\n\n**Duplicate titles are rejected** — the API enforces unique \`display_title\` per workspace.\nWhen uploading multiple skills, failures are non-fatal; partial results are reported.\n\n### Managed Settings (Claude Code plugins)\n\nFor enterprise-wide Claude Code plugin deployment (not the Skills API), use managed settings\npushed via MDM (Jamf, Intune, SCCM, etc.):\n\n| Platform | Path |\n|---|---|\n| macOS | \`/Library/Application Support/ClaudeCode/managed-settings.json\` |\n| Linux | \`/etc/claude-code/managed-settings.json\` |\n| Windows | \`C:\\Program Files\\ClaudeCode\\managed-settings.json\` |\n\nManaged settings are **highest priority** in the settings cascade — they override user settings.\nUse this to force-enable plugins, lock down permissions, or configure organization defaults.\n\n\`\`\`json\n{\n \"enabledPlugins\": {\n \"my-plugin@my-marketplace\": true\n }\n}\n\`\`\`\n\nCombine with \`npm install -g <package>\` (via IT software deployment) to install the plugin\nbinary, then managed settings to enable it across all machines.\n\n## Not Yet Implemented\n\nThese commands exist with the correct CLI shape but return structured\n\`not-yet-implemented\` stubs (exit 1). Coming in a future release:\n\n- \`org users update/remove\` — role changes, offboarding\n- \`org invites create/delete\` — programmatic invitations\n- \`org workspaces create/archive\` — workspace lifecycle\n- \`org workspaces members add/update/remove\` — workspace membership\n- \`org api-keys update\` — rename keys\n";
|
|
11
|
+
|
|
12
|
+
export const fragments = {
|
|
13
|
+
twoWaysToUseIt: {
|
|
14
|
+
header: "## Two Ways to Use It",
|
|
15
|
+
body: "### CLI — Quick Queries\n\n\`\`\`bash\nvat claude org info # Org identity\nvat claude org users list # All members\nvat claude org api-keys list --status active # Active API keys\nvat claude org cost --group-by description # Cost breakdown by model\nvat claude org usage --from 2025-01-01T00:00:00Z # Token usage since Jan\nvat claude org skills list # Workspace-scoped skills (requires ANTHROPIC_API_KEY)\n\`\`\`\n\n### Library — Scripts and Automation\n\n\`\`\`typescript\nimport { OrgApiClient, createOrgApiClientFromEnv } from \'@vibe-agent-toolkit/claude-marketplace\';\n\n// Reads ANTHROPIC_ADMIN_API_KEY and optionally ANTHROPIC_API_KEY from env\nconst client = createOrgApiClientFromEnv();\n\n// Or construct directly\nconst client = new OrgApiClient({\n adminApiKey: \'sk-ant-admin-...\',\n apiKey: \'sk-ant-api03-...\', // only needed for skills endpoints\n});\n\`\`\`",
|
|
16
|
+
text: "## Two Ways to Use It\n\n### CLI — Quick Queries\n\n\`\`\`bash\nvat claude org info # Org identity\nvat claude org users list # All members\nvat claude org api-keys list --status active # Active API keys\nvat claude org cost --group-by description # Cost breakdown by model\nvat claude org usage --from 2025-01-01T00:00:00Z # Token usage since Jan\nvat claude org skills list # Workspace-scoped skills (requires ANTHROPIC_API_KEY)\n\`\`\`\n\n### Library — Scripts and Automation\n\n\`\`\`typescript\nimport { OrgApiClient, createOrgApiClientFromEnv } from \'@vibe-agent-toolkit/claude-marketplace\';\n\n// Reads ANTHROPIC_ADMIN_API_KEY and optionally ANTHROPIC_API_KEY from env\nconst client = createOrgApiClientFromEnv();\n\n// Or construct directly\nconst client = new OrgApiClient({\n adminApiKey: \'sk-ant-admin-...\',\n apiKey: \'sk-ant-api03-...\', // only needed for skills endpoints\n});\n\`\`\`"
|
|
17
|
+
},
|
|
18
|
+
apiReference: {
|
|
19
|
+
header: "## API Reference",
|
|
20
|
+
body: "### Auth: Two Keys, Two Surfaces\n\n| Key | Env Var | Endpoints | Who Has It |\n|---|---|---|---|\n| Admin API key | \`ANTHROPIC_ADMIN_API_KEY\` | \`/v1/organizations/*\` | Org admins only |\n| Regular API key | \`ANTHROPIC_API_KEY\` | \`/v1/skills\` (beta) | Any workspace member |\n\n### Endpoints and Methods\n\n**Org identity:**\n\`\`\`typescript\nconst org = await client.get<{ id: string; type: string; name: string }>(\'/v1/organizations/me\');\n\`\`\`\n\n**Users:**\n\`\`\`typescript\n// List (paginated with limit/after_id)\nconst users = await client.get<{ data: OrgUser[]; has_more: boolean }>(\n \'/v1/organizations/users\', { limit: 100 }\n);\n\n// Get single user\nconst user = await client.get<OrgUser>(\'/v1/organizations/users/user_abc123\');\n\`\`\`\n\n**Invites:**\n\`\`\`typescript\nconst invites = await client.get<{ data: OrgInvite[]; has_more: boolean }>(\n \'/v1/organizations/invites\'\n);\n\`\`\`\n\n**Workspaces:**\n\`\`\`typescript\nconst workspaces = await client.get<{ data: OrgWorkspace[]; has_more: boolean }>(\n \'/v1/organizations/workspaces\'\n);\n\n// Workspace members\nconst members = await client.get<{ data: WorkspaceMember[]; has_more: boolean }>(\n \'/v1/organizations/workspaces/ws_abc/members\'\n);\n\`\`\`\n\n**API keys:**\n\`\`\`typescript\nconst keys = await client.get<{ data: ApiKey[]; has_more: boolean }>(\n \'/v1/organizations/api_keys\',\n { status: \'active\', workspace_id: \'ws_abc\' } // both filters optional\n);\n\`\`\`\n\n**Skills (beta — uses regular API key):**\n\`\`\`typescript\n// List skills\nconst skills = await client.getSkills<{ data: Skill[]; has_more: boolean }>(\'/v1/skills\');\n// Adds anthropic-beta: skills-2025-10-02 header automatically\n\n// Upload a skill (multipart/form-data)\nimport { buildMultipartFormData } from \'@vibe-agent-toolkit/claude-marketplace\';\nconst multipart = buildMultipartFormData(\n { display_title: \'My Skill\' },\n [{ fieldName: \'files[]\', filename: \'SKILL.md\', content: Buffer.from(skillContent) }],\n);\nconst created = await client.uploadSkill<{ id: string; latest_version: string }>(multipart);\n\n// Delete a skill\nconst deleted = await client.deleteSkill<{ id: string; type: string }>(skillId);\n\`\`\`\n\n### Report Endpoints — Pagination Quirk\n\nUsage, cost, and code-analytics endpoints have a **non-standard pagination model**.\nThey return \`has_more: true\` with a \`next_page\` cursor, but the API **rejects \`next_page\`\nas a query parameter**. Paginate by advancing \`starting_at\` to the last bucket\'s \`ending_at\`.\n\n**Usage report (daily token buckets):**\n\`\`\`typescript\ninterface UsageBucket {\n starting_at: string;\n ending_at: string;\n results: Array<{\n uncached_input_tokens: number;\n cache_read_input_tokens: number;\n output_tokens: number;\n model: string | null;\n workspace_id: string | null;\n api_key_id: string | null;\n service_tier: string | null;\n // ... other dimension fields, null if not applicable\n }>;\n}\n\n// First page\nlet resp = await client.get<{ data: UsageBucket[]; has_more: boolean }>(\n \'/v1/organizations/usage_report/messages\',\n { starting_at: \'2025-01-01T00:00:00Z\', ending_at: \'2025-12-31T23:59:59Z\' }\n);\n\n// Subsequent pages — advance starting_at, do NOT pass next_page\nconst lastBucket = resp.data.at(-1);\nresp = await client.get<{ data: UsageBucket[]; has_more: boolean }>(\n \'/v1/organizations/usage_report/messages\',\n { starting_at: lastBucket.ending_at, ending_at: \'2025-12-31T23:59:59Z\' }\n);\n\`\`\`\n\n**Cost report:**\n\`\`\`typescript\n// amount is a STRING, not a number — parse before arithmetic\ninterface CostResult {\n currency: string;\n amount: string; // \"7.0812\" — use parseFloat()\n description: string | null;\n model: string | null;\n token_type: string | null;\n // ...\n}\n\n// group_by[] needs URLSearchParams for repeated params\nconst qs = new URLSearchParams();\nqs.set(\'starting_at\', \'2025-03-01T00:00:00Z\');\nqs.set(\'ending_at\', \'2025-03-31T23:59:59Z\');\nqs.append(\'group_by[]\', \'description\');\nqs.append(\'group_by[]\', \'workspace_id\');\nconst resp = await client.get<{ data: CostBucket[] }>(\n \`/v1/organizations/cost_report?${qs.toString()}\`\n);\n\n// Sum costs\nconst total = resp.data\n .flatMap(b => b.results)\n .reduce((sum, r) => sum + parseFloat(r.amount), 0);\n\`\`\`\n\n**Code analytics (Claude Code productivity):**\n\`\`\`typescript\n// Date-only format YYYY-MM-DD. No ending_at parameter.\nconst resp = await client.get<{ data: unknown[] }>(\n \'/v1/organizations/usage_report/claude_code\',\n { starting_at: \'2025-03-01\' } // NOT ISO datetime\n);\n// Returns empty data[] when no Claude Code enterprise seats are active\n\`\`\`",
|
|
21
|
+
text: "## API Reference\n\n### Auth: Two Keys, Two Surfaces\n\n| Key | Env Var | Endpoints | Who Has It |\n|---|---|---|---|\n| Admin API key | \`ANTHROPIC_ADMIN_API_KEY\` | \`/v1/organizations/*\` | Org admins only |\n| Regular API key | \`ANTHROPIC_API_KEY\` | \`/v1/skills\` (beta) | Any workspace member |\n\n### Endpoints and Methods\n\n**Org identity:**\n\`\`\`typescript\nconst org = await client.get<{ id: string; type: string; name: string }>(\'/v1/organizations/me\');\n\`\`\`\n\n**Users:**\n\`\`\`typescript\n// List (paginated with limit/after_id)\nconst users = await client.get<{ data: OrgUser[]; has_more: boolean }>(\n \'/v1/organizations/users\', { limit: 100 }\n);\n\n// Get single user\nconst user = await client.get<OrgUser>(\'/v1/organizations/users/user_abc123\');\n\`\`\`\n\n**Invites:**\n\`\`\`typescript\nconst invites = await client.get<{ data: OrgInvite[]; has_more: boolean }>(\n \'/v1/organizations/invites\'\n);\n\`\`\`\n\n**Workspaces:**\n\`\`\`typescript\nconst workspaces = await client.get<{ data: OrgWorkspace[]; has_more: boolean }>(\n \'/v1/organizations/workspaces\'\n);\n\n// Workspace members\nconst members = await client.get<{ data: WorkspaceMember[]; has_more: boolean }>(\n \'/v1/organizations/workspaces/ws_abc/members\'\n);\n\`\`\`\n\n**API keys:**\n\`\`\`typescript\nconst keys = await client.get<{ data: ApiKey[]; has_more: boolean }>(\n \'/v1/organizations/api_keys\',\n { status: \'active\', workspace_id: \'ws_abc\' } // both filters optional\n);\n\`\`\`\n\n**Skills (beta — uses regular API key):**\n\`\`\`typescript\n// List skills\nconst skills = await client.getSkills<{ data: Skill[]; has_more: boolean }>(\'/v1/skills\');\n// Adds anthropic-beta: skills-2025-10-02 header automatically\n\n// Upload a skill (multipart/form-data)\nimport { buildMultipartFormData } from \'@vibe-agent-toolkit/claude-marketplace\';\nconst multipart = buildMultipartFormData(\n { display_title: \'My Skill\' },\n [{ fieldName: \'files[]\', filename: \'SKILL.md\', content: Buffer.from(skillContent) }],\n);\nconst created = await client.uploadSkill<{ id: string; latest_version: string }>(multipart);\n\n// Delete a skill\nconst deleted = await client.deleteSkill<{ id: string; type: string }>(skillId);\n\`\`\`\n\n### Report Endpoints — Pagination Quirk\n\nUsage, cost, and code-analytics endpoints have a **non-standard pagination model**.\nThey return \`has_more: true\` with a \`next_page\` cursor, but the API **rejects \`next_page\`\nas a query parameter**. Paginate by advancing \`starting_at\` to the last bucket\'s \`ending_at\`.\n\n**Usage report (daily token buckets):**\n\`\`\`typescript\ninterface UsageBucket {\n starting_at: string;\n ending_at: string;\n results: Array<{\n uncached_input_tokens: number;\n cache_read_input_tokens: number;\n output_tokens: number;\n model: string | null;\n workspace_id: string | null;\n api_key_id: string | null;\n service_tier: string | null;\n // ... other dimension fields, null if not applicable\n }>;\n}\n\n// First page\nlet resp = await client.get<{ data: UsageBucket[]; has_more: boolean }>(\n \'/v1/organizations/usage_report/messages\',\n { starting_at: \'2025-01-01T00:00:00Z\', ending_at: \'2025-12-31T23:59:59Z\' }\n);\n\n// Subsequent pages — advance starting_at, do NOT pass next_page\nconst lastBucket = resp.data.at(-1);\nresp = await client.get<{ data: UsageBucket[]; has_more: boolean }>(\n \'/v1/organizations/usage_report/messages\',\n { starting_at: lastBucket.ending_at, ending_at: \'2025-12-31T23:59:59Z\' }\n);\n\`\`\`\n\n**Cost report:**\n\`\`\`typescript\n// amount is a STRING, not a number — parse before arithmetic\ninterface CostResult {\n currency: string;\n amount: string; // \"7.0812\" — use parseFloat()\n description: string | null;\n model: string | null;\n token_type: string | null;\n // ...\n}\n\n// group_by[] needs URLSearchParams for repeated params\nconst qs = new URLSearchParams();\nqs.set(\'starting_at\', \'2025-03-01T00:00:00Z\');\nqs.set(\'ending_at\', \'2025-03-31T23:59:59Z\');\nqs.append(\'group_by[]\', \'description\');\nqs.append(\'group_by[]\', \'workspace_id\');\nconst resp = await client.get<{ data: CostBucket[] }>(\n \`/v1/organizations/cost_report?${qs.toString()}\`\n);\n\n// Sum costs\nconst total = resp.data\n .flatMap(b => b.results)\n .reduce((sum, r) => sum + parseFloat(r.amount), 0);\n\`\`\`\n\n**Code analytics (Claude Code productivity):**\n\`\`\`typescript\n// Date-only format YYYY-MM-DD. No ending_at parameter.\nconst resp = await client.get<{ data: unknown[] }>(\n \'/v1/organizations/usage_report/claude_code\',\n { starting_at: \'2025-03-01\' } // NOT ISO datetime\n);\n// Returns empty data[] when no Claude Code enterprise seats are active\n\`\`\`"
|
|
22
|
+
},
|
|
23
|
+
commonRecipes: {
|
|
24
|
+
header: "## Common Recipes",
|
|
25
|
+
body: "### Monthly cost summary script\n\n\`\`\`typescript\nimport { createOrgApiClientFromEnv } from \'@vibe-agent-toolkit/claude-marketplace\';\n\nconst client = createOrgApiClientFromEnv();\nconst qs = new URLSearchParams();\nqs.set(\'starting_at\', \'2025-03-01T00:00:00Z\');\nqs.set(\'ending_at\', \'2025-04-01T00:00:00Z\');\nqs.append(\'group_by[]\', \'description\');\n\nconst allResults = [];\nlet startingAt = \'2025-03-01T00:00:00Z\';\nlet hasMore = true;\n\nwhile (hasMore) {\n qs.set(\'starting_at\', startingAt);\n const resp = await client.get(\`/v1/organizations/cost_report?${qs.toString()}\`);\n allResults.push(...resp.data);\n const last = resp.data.at(-1);\n hasMore = resp.has_more && last;\n if (last) startingAt = last.ending_at;\n}\n\nconst byDescription = new Map();\nfor (const bucket of allResults) {\n for (const r of bucket.results) {\n const key = r.description ?? \'unclassified\';\n byDescription.set(key, (byDescription.get(key) ?? 0) + parseFloat(r.amount));\n }\n}\nfor (const [desc, total] of byDescription) {\n console.log(\`${desc}: $${total.toFixed(2)}\`);\n}\n\`\`\`\n\n### API key security audit\n\n\`\`\`typescript\nconst client = createOrgApiClientFromEnv();\nconst { data: keys } = await client.get(\'/v1/organizations/api_keys\', { limit: 100 });\n\nconst issues = [];\nfor (const key of keys) {\n if (key.status === \'active\' && !key.expires_at) {\n issues.push(\`${key.name}: active with no expiry\`);\n }\n if (key.status === \'active\' && !key.workspace_id) {\n issues.push(\`${key.name}: not scoped to a workspace\`);\n }\n}\nconsole.log(issues.length ? issues.join(\'\\n\') : \'All keys look good\');\n\`\`\`\n\n### List org users who haven\'t accepted invites\n\n\`\`\`typescript\nconst client = createOrgApiClientFromEnv();\nconst { data: invites } = await client.get(\'/v1/organizations/invites\');\nconst pending = invites.filter(i => i.status !== \'accepted\');\nconsole.log(\`${pending.length} pending invites:\`, pending.map(i => i.email));\n\`\`\`",
|
|
26
|
+
text: "## Common Recipes\n\n### Monthly cost summary script\n\n\`\`\`typescript\nimport { createOrgApiClientFromEnv } from \'@vibe-agent-toolkit/claude-marketplace\';\n\nconst client = createOrgApiClientFromEnv();\nconst qs = new URLSearchParams();\nqs.set(\'starting_at\', \'2025-03-01T00:00:00Z\');\nqs.set(\'ending_at\', \'2025-04-01T00:00:00Z\');\nqs.append(\'group_by[]\', \'description\');\n\nconst allResults = [];\nlet startingAt = \'2025-03-01T00:00:00Z\';\nlet hasMore = true;\n\nwhile (hasMore) {\n qs.set(\'starting_at\', startingAt);\n const resp = await client.get(\`/v1/organizations/cost_report?${qs.toString()}\`);\n allResults.push(...resp.data);\n const last = resp.data.at(-1);\n hasMore = resp.has_more && last;\n if (last) startingAt = last.ending_at;\n}\n\nconst byDescription = new Map();\nfor (const bucket of allResults) {\n for (const r of bucket.results) {\n const key = r.description ?? \'unclassified\';\n byDescription.set(key, (byDescription.get(key) ?? 0) + parseFloat(r.amount));\n }\n}\nfor (const [desc, total] of byDescription) {\n console.log(\`${desc}: $${total.toFixed(2)}\`);\n}\n\`\`\`\n\n### API key security audit\n\n\`\`\`typescript\nconst client = createOrgApiClientFromEnv();\nconst { data: keys } = await client.get(\'/v1/organizations/api_keys\', { limit: 100 });\n\nconst issues = [];\nfor (const key of keys) {\n if (key.status === \'active\' && !key.expires_at) {\n issues.push(\`${key.name}: active with no expiry\`);\n }\n if (key.status === \'active\' && !key.workspace_id) {\n issues.push(\`${key.name}: not scoped to a workspace\`);\n }\n}\nconsole.log(issues.length ? issues.join(\'\\n\') : \'All keys look good\');\n\`\`\`\n\n### List org users who haven\'t accepted invites\n\n\`\`\`typescript\nconst client = createOrgApiClientFromEnv();\nconst { data: invites } = await client.get(\'/v1/organizations/invites\');\nconst pending = invites.filter(i => i.status !== \'accepted\');\nconsole.log(\`${pending.length} pending invites:\`, pending.map(i => i.email));\n\`\`\`"
|
|
27
|
+
},
|
|
28
|
+
cliReference: {
|
|
29
|
+
header: "## CLI Reference",
|
|
30
|
+
body: "All commands require \`ANTHROPIC_ADMIN_API_KEY\` unless noted.\n\n\`\`\`\nvat claude org info Org identity (id, name)\nvat claude org users list [--limit N] List members\nvat claude org users get <user-id> Get single member\nvat claude org invites list List invitations\nvat claude org workspaces list List API workspaces\nvat claude org workspaces get <id> Get single workspace\nvat claude org workspaces members list <id> Workspace members\nvat claude org api-keys list [--status S] API key inventory\nvat claude org usage [--from DT] [--to DT] Token usage report\nvat claude org cost [--from DT] [--group-by F] USD cost report\nvat claude org code-analytics [--from DATE] Claude Code metrics (YYYY-MM-DD)\nvat claude org skills list Workspace skills (needs ANTHROPIC_API_KEY)\nvat claude org skills install <source> Upload skill dir or ZIP to org\nvat claude org skills delete <skill-id> Delete a skill (versions first)\nvat claude org skills versions list <skill-id> List skill versions\nvat claude org skills versions delete <id> <ver> Delete a skill version\n\`\`\`\n\nExit codes: \`0\` success, \`1\` expected failure (stubs), \`2\` system error (missing key, API error).\n\n**Skill deletion lifecycle:** The API requires all versions to be deleted before the skill itself.\nUse \`versions list\` to find versions, \`versions delete\` each one, then \`delete\` the skill.",
|
|
31
|
+
text: "## CLI Reference\n\nAll commands require \`ANTHROPIC_ADMIN_API_KEY\` unless noted.\n\n\`\`\`\nvat claude org info Org identity (id, name)\nvat claude org users list [--limit N] List members\nvat claude org users get <user-id> Get single member\nvat claude org invites list List invitations\nvat claude org workspaces list List API workspaces\nvat claude org workspaces get <id> Get single workspace\nvat claude org workspaces members list <id> Workspace members\nvat claude org api-keys list [--status S] API key inventory\nvat claude org usage [--from DT] [--to DT] Token usage report\nvat claude org cost [--from DT] [--group-by F] USD cost report\nvat claude org code-analytics [--from DATE] Claude Code metrics (YYYY-MM-DD)\nvat claude org skills list Workspace skills (needs ANTHROPIC_API_KEY)\nvat claude org skills install <source> Upload skill dir or ZIP to org\nvat claude org skills delete <skill-id> Delete a skill (versions first)\nvat claude org skills versions list <skill-id> List skill versions\nvat claude org skills versions delete <id> <ver> Delete a skill version\n\`\`\`\n\nExit codes: \`0\` success, \`1\` expected failure (stubs), \`2\` system error (missing key, API error).\n\n**Skill deletion lifecycle:** The API requires all versions to be deleted before the skill itself.\nUse \`versions list\` to find versions, \`versions delete\` each one, then \`delete\` the skill."
|
|
32
|
+
},
|
|
33
|
+
enterpriseSkillDistribution: {
|
|
34
|
+
header: "## Enterprise Skill Distribution",
|
|
35
|
+
body: "### Skills API (claude.ai / Console)\n\nSkills uploaded via \`POST /v1/skills\` are **workspace-scoped** and **automatically available to\nall workspace members**. There is no per-user enable/disable via the API — visibility is\nworkspace-level only. The admin UI may have additional controls not exposed in the API.\n\n**Upload from npm package:**\n\`\`\`bash\n# Upload all skills from a package\nvat claude org skills install --from-npm @scope/my-skills-package@1.0.0\n\n# Upload a single skill\nvat claude org skills install --from-npm @scope/my-skills-package@1.0.0 --skill my-skill\n\`\`\`\n\nThe package must contain \`dist/skills/<name>/SKILL.md\` (produced by \`vat skills build\`).\nIf skills are in a sub-dependency, the command searches \`node_modules/*/dist/skills/\` too.\n\n**Duplicate titles are rejected** — the API enforces unique \`display_title\` per workspace.\nWhen uploading multiple skills, failures are non-fatal; partial results are reported.\n\n### Managed Settings (Claude Code plugins)\n\nFor enterprise-wide Claude Code plugin deployment (not the Skills API), use managed settings\npushed via MDM (Jamf, Intune, SCCM, etc.):\n\n| Platform | Path |\n|---|---|\n| macOS | \`/Library/Application Support/ClaudeCode/managed-settings.json\` |\n| Linux | \`/etc/claude-code/managed-settings.json\` |\n| Windows | \`C:\\Program Files\\ClaudeCode\\managed-settings.json\` |\n\nManaged settings are **highest priority** in the settings cascade — they override user settings.\nUse this to force-enable plugins, lock down permissions, or configure organization defaults.\n\n\`\`\`json\n{\n \"enabledPlugins\": {\n \"my-plugin@my-marketplace\": true\n }\n}\n\`\`\`\n\nCombine with \`npm install -g <package>\` (via IT software deployment) to install the plugin\nbinary, then managed settings to enable it across all machines.",
|
|
36
|
+
text: "## Enterprise Skill Distribution\n\n### Skills API (claude.ai / Console)\n\nSkills uploaded via \`POST /v1/skills\` are **workspace-scoped** and **automatically available to\nall workspace members**. There is no per-user enable/disable via the API — visibility is\nworkspace-level only. The admin UI may have additional controls not exposed in the API.\n\n**Upload from npm package:**\n\`\`\`bash\n# Upload all skills from a package\nvat claude org skills install --from-npm @scope/my-skills-package@1.0.0\n\n# Upload a single skill\nvat claude org skills install --from-npm @scope/my-skills-package@1.0.0 --skill my-skill\n\`\`\`\n\nThe package must contain \`dist/skills/<name>/SKILL.md\` (produced by \`vat skills build\`).\nIf skills are in a sub-dependency, the command searches \`node_modules/*/dist/skills/\` too.\n\n**Duplicate titles are rejected** — the API enforces unique \`display_title\` per workspace.\nWhen uploading multiple skills, failures are non-fatal; partial results are reported.\n\n### Managed Settings (Claude Code plugins)\n\nFor enterprise-wide Claude Code plugin deployment (not the Skills API), use managed settings\npushed via MDM (Jamf, Intune, SCCM, etc.):\n\n| Platform | Path |\n|---|---|\n| macOS | \`/Library/Application Support/ClaudeCode/managed-settings.json\` |\n| Linux | \`/etc/claude-code/managed-settings.json\` |\n| Windows | \`C:\\Program Files\\ClaudeCode\\managed-settings.json\` |\n\nManaged settings are **highest priority** in the settings cascade — they override user settings.\nUse this to force-enable plugins, lock down permissions, or configure organization defaults.\n\n\`\`\`json\n{\n \"enabledPlugins\": {\n \"my-plugin@my-marketplace\": true\n }\n}\n\`\`\`\n\nCombine with \`npm install -g <package>\` (via IT software deployment) to install the plugin\nbinary, then managed settings to enable it across all machines."
|
|
37
|
+
},
|
|
38
|
+
notYetImplemented: {
|
|
39
|
+
header: "## Not Yet Implemented",
|
|
40
|
+
body: "These commands exist with the correct CLI shape but return structured\n\`not-yet-implemented\` stubs (exit 1). Coming in a future release:\n\n- \`org users update/remove\` — role changes, offboarding\n- \`org invites create/delete\` — programmatic invitations\n- \`org workspaces create/archive\` — workspace lifecycle\n- \`org workspaces members add/update/remove\` — workspace membership\n- \`org api-keys update\` — rename keys",
|
|
41
|
+
text: "## Not Yet Implemented\n\nThese commands exist with the correct CLI shape but return structured\n\`not-yet-implemented\` stubs (exit 1). Coming in a future release:\n\n- \`org users update/remove\` — role changes, offboarding\n- \`org invites create/delete\` — programmatic invitations\n- \`org workspaces create/archive\` — workspace lifecycle\n- \`org workspaces members add/update/remove\` — workspace membership\n- \`org api-keys update\` — rename keys"
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: org-admin
|
|
3
|
+
description: Anthropic org administration for Enterprise/Team admins. Requires ANTHROPIC_ADMIN_API_KEY. Use for org user management, API key auditing, cost/usage reporting, workspace administration, and enterprise skill distribution via the Anthropic Admin API. Not for regular users — admin access required.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Claude Org Administration
|
|
7
|
+
|
|
8
|
+
**For Anthropic org admins only.** Requires `ANTHROPIC_ADMIN_API_KEY` (Enterprise/Team plan).
|
|
9
|
+
If you don't have an admin key, this skill is not for you — use `vibe-agent-toolkit:distribution`
|
|
10
|
+
for local plugin management instead.
|
|
11
|
+
|
|
12
|
+
## Two Ways to Use It
|
|
13
|
+
|
|
14
|
+
### CLI — Quick Queries
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
vat claude org info # Org identity
|
|
18
|
+
vat claude org users list # All members
|
|
19
|
+
vat claude org api-keys list --status active # Active API keys
|
|
20
|
+
vat claude org cost --group-by description # Cost breakdown by model
|
|
21
|
+
vat claude org usage --from 2025-01-01T00:00:00Z # Token usage since Jan
|
|
22
|
+
vat claude org skills list # Workspace-scoped skills (requires ANTHROPIC_API_KEY)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Library — Scripts and Automation
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { OrgApiClient, createOrgApiClientFromEnv } from '@vibe-agent-toolkit/claude-marketplace';
|
|
29
|
+
|
|
30
|
+
// Reads ANTHROPIC_ADMIN_API_KEY and optionally ANTHROPIC_API_KEY from env
|
|
31
|
+
const client = createOrgApiClientFromEnv();
|
|
32
|
+
|
|
33
|
+
// Or construct directly
|
|
34
|
+
const client = new OrgApiClient({
|
|
35
|
+
adminApiKey: 'sk-ant-admin-...',
|
|
36
|
+
apiKey: 'sk-ant-api03-...', // only needed for skills endpoints
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## API Reference
|
|
41
|
+
|
|
42
|
+
### Auth: Two Keys, Two Surfaces
|
|
43
|
+
|
|
44
|
+
| Key | Env Var | Endpoints | Who Has It |
|
|
45
|
+
|---|---|---|---|
|
|
46
|
+
| Admin API key | `ANTHROPIC_ADMIN_API_KEY` | `/v1/organizations/*` | Org admins only |
|
|
47
|
+
| Regular API key | `ANTHROPIC_API_KEY` | `/v1/skills` (beta) | Any workspace member |
|
|
48
|
+
|
|
49
|
+
### Endpoints and Methods
|
|
50
|
+
|
|
51
|
+
**Org identity:**
|
|
52
|
+
```typescript
|
|
53
|
+
const org = await client.get<{ id: string; type: string; name: string }>('/v1/organizations/me');
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Users:**
|
|
57
|
+
```typescript
|
|
58
|
+
// List (paginated with limit/after_id)
|
|
59
|
+
const users = await client.get<{ data: OrgUser[]; has_more: boolean }>(
|
|
60
|
+
'/v1/organizations/users', { limit: 100 }
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
// Get single user
|
|
64
|
+
const user = await client.get<OrgUser>('/v1/organizations/users/user_abc123');
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Invites:**
|
|
68
|
+
```typescript
|
|
69
|
+
const invites = await client.get<{ data: OrgInvite[]; has_more: boolean }>(
|
|
70
|
+
'/v1/organizations/invites'
|
|
71
|
+
);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Workspaces:**
|
|
75
|
+
```typescript
|
|
76
|
+
const workspaces = await client.get<{ data: OrgWorkspace[]; has_more: boolean }>(
|
|
77
|
+
'/v1/organizations/workspaces'
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Workspace members
|
|
81
|
+
const members = await client.get<{ data: WorkspaceMember[]; has_more: boolean }>(
|
|
82
|
+
'/v1/organizations/workspaces/ws_abc/members'
|
|
83
|
+
);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**API keys:**
|
|
87
|
+
```typescript
|
|
88
|
+
const keys = await client.get<{ data: ApiKey[]; has_more: boolean }>(
|
|
89
|
+
'/v1/organizations/api_keys',
|
|
90
|
+
{ status: 'active', workspace_id: 'ws_abc' } // both filters optional
|
|
91
|
+
);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Skills (beta — uses regular API key):**
|
|
95
|
+
```typescript
|
|
96
|
+
// List skills
|
|
97
|
+
const skills = await client.getSkills<{ data: Skill[]; has_more: boolean }>('/v1/skills');
|
|
98
|
+
// Adds anthropic-beta: skills-2025-10-02 header automatically
|
|
99
|
+
|
|
100
|
+
// Upload a skill (multipart/form-data)
|
|
101
|
+
import { buildMultipartFormData } from '@vibe-agent-toolkit/claude-marketplace';
|
|
102
|
+
const multipart = buildMultipartFormData(
|
|
103
|
+
{ display_title: 'My Skill' },
|
|
104
|
+
[{ fieldName: 'files[]', filename: 'SKILL.md', content: Buffer.from(skillContent) }],
|
|
105
|
+
);
|
|
106
|
+
const created = await client.uploadSkill<{ id: string; latest_version: string }>(multipart);
|
|
107
|
+
|
|
108
|
+
// Delete a skill
|
|
109
|
+
const deleted = await client.deleteSkill<{ id: string; type: string }>(skillId);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Report Endpoints — Pagination Quirk
|
|
113
|
+
|
|
114
|
+
Usage, cost, and code-analytics endpoints have a **non-standard pagination model**.
|
|
115
|
+
They return `has_more: true` with a `next_page` cursor, but the API **rejects `next_page`
|
|
116
|
+
as a query parameter**. Paginate by advancing `starting_at` to the last bucket's `ending_at`.
|
|
117
|
+
|
|
118
|
+
**Usage report (daily token buckets):**
|
|
119
|
+
```typescript
|
|
120
|
+
interface UsageBucket {
|
|
121
|
+
starting_at: string;
|
|
122
|
+
ending_at: string;
|
|
123
|
+
results: Array<{
|
|
124
|
+
uncached_input_tokens: number;
|
|
125
|
+
cache_read_input_tokens: number;
|
|
126
|
+
output_tokens: number;
|
|
127
|
+
model: string | null;
|
|
128
|
+
workspace_id: string | null;
|
|
129
|
+
api_key_id: string | null;
|
|
130
|
+
service_tier: string | null;
|
|
131
|
+
// ... other dimension fields, null if not applicable
|
|
132
|
+
}>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// First page
|
|
136
|
+
let resp = await client.get<{ data: UsageBucket[]; has_more: boolean }>(
|
|
137
|
+
'/v1/organizations/usage_report/messages',
|
|
138
|
+
{ starting_at: '2025-01-01T00:00:00Z', ending_at: '2025-12-31T23:59:59Z' }
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// Subsequent pages — advance starting_at, do NOT pass next_page
|
|
142
|
+
const lastBucket = resp.data.at(-1);
|
|
143
|
+
resp = await client.get<{ data: UsageBucket[]; has_more: boolean }>(
|
|
144
|
+
'/v1/organizations/usage_report/messages',
|
|
145
|
+
{ starting_at: lastBucket.ending_at, ending_at: '2025-12-31T23:59:59Z' }
|
|
146
|
+
);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Cost report:**
|
|
150
|
+
```typescript
|
|
151
|
+
// amount is a STRING, not a number — parse before arithmetic
|
|
152
|
+
interface CostResult {
|
|
153
|
+
currency: string;
|
|
154
|
+
amount: string; // "7.0812" — use parseFloat()
|
|
155
|
+
description: string | null;
|
|
156
|
+
model: string | null;
|
|
157
|
+
token_type: string | null;
|
|
158
|
+
// ...
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// group_by[] needs URLSearchParams for repeated params
|
|
162
|
+
const qs = new URLSearchParams();
|
|
163
|
+
qs.set('starting_at', '2025-03-01T00:00:00Z');
|
|
164
|
+
qs.set('ending_at', '2025-03-31T23:59:59Z');
|
|
165
|
+
qs.append('group_by[]', 'description');
|
|
166
|
+
qs.append('group_by[]', 'workspace_id');
|
|
167
|
+
const resp = await client.get<{ data: CostBucket[] }>(
|
|
168
|
+
`/v1/organizations/cost_report?${qs.toString()}`
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// Sum costs
|
|
172
|
+
const total = resp.data
|
|
173
|
+
.flatMap(b => b.results)
|
|
174
|
+
.reduce((sum, r) => sum + parseFloat(r.amount), 0);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Code analytics (Claude Code productivity):**
|
|
178
|
+
```typescript
|
|
179
|
+
// Date-only format YYYY-MM-DD. No ending_at parameter.
|
|
180
|
+
const resp = await client.get<{ data: unknown[] }>(
|
|
181
|
+
'/v1/organizations/usage_report/claude_code',
|
|
182
|
+
{ starting_at: '2025-03-01' } // NOT ISO datetime
|
|
183
|
+
);
|
|
184
|
+
// Returns empty data[] when no Claude Code enterprise seats are active
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Common Recipes
|
|
188
|
+
|
|
189
|
+
### Monthly cost summary script
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import { createOrgApiClientFromEnv } from '@vibe-agent-toolkit/claude-marketplace';
|
|
193
|
+
|
|
194
|
+
const client = createOrgApiClientFromEnv();
|
|
195
|
+
const qs = new URLSearchParams();
|
|
196
|
+
qs.set('starting_at', '2025-03-01T00:00:00Z');
|
|
197
|
+
qs.set('ending_at', '2025-04-01T00:00:00Z');
|
|
198
|
+
qs.append('group_by[]', 'description');
|
|
199
|
+
|
|
200
|
+
const allResults = [];
|
|
201
|
+
let startingAt = '2025-03-01T00:00:00Z';
|
|
202
|
+
let hasMore = true;
|
|
203
|
+
|
|
204
|
+
while (hasMore) {
|
|
205
|
+
qs.set('starting_at', startingAt);
|
|
206
|
+
const resp = await client.get(`/v1/organizations/cost_report?${qs.toString()}`);
|
|
207
|
+
allResults.push(...resp.data);
|
|
208
|
+
const last = resp.data.at(-1);
|
|
209
|
+
hasMore = resp.has_more && last;
|
|
210
|
+
if (last) startingAt = last.ending_at;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const byDescription = new Map();
|
|
214
|
+
for (const bucket of allResults) {
|
|
215
|
+
for (const r of bucket.results) {
|
|
216
|
+
const key = r.description ?? 'unclassified';
|
|
217
|
+
byDescription.set(key, (byDescription.get(key) ?? 0) + parseFloat(r.amount));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
for (const [desc, total] of byDescription) {
|
|
221
|
+
console.log(`${desc}: $${total.toFixed(2)}`);
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### API key security audit
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
const client = createOrgApiClientFromEnv();
|
|
229
|
+
const { data: keys } = await client.get('/v1/organizations/api_keys', { limit: 100 });
|
|
230
|
+
|
|
231
|
+
const issues = [];
|
|
232
|
+
for (const key of keys) {
|
|
233
|
+
if (key.status === 'active' && !key.expires_at) {
|
|
234
|
+
issues.push(`${key.name}: active with no expiry`);
|
|
235
|
+
}
|
|
236
|
+
if (key.status === 'active' && !key.workspace_id) {
|
|
237
|
+
issues.push(`${key.name}: not scoped to a workspace`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
console.log(issues.length ? issues.join('\n') : 'All keys look good');
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### List org users who haven't accepted invites
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
const client = createOrgApiClientFromEnv();
|
|
247
|
+
const { data: invites } = await client.get('/v1/organizations/invites');
|
|
248
|
+
const pending = invites.filter(i => i.status !== 'accepted');
|
|
249
|
+
console.log(`${pending.length} pending invites:`, pending.map(i => i.email));
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## CLI Reference
|
|
253
|
+
|
|
254
|
+
All commands require `ANTHROPIC_ADMIN_API_KEY` unless noted.
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
vat claude org info Org identity (id, name)
|
|
258
|
+
vat claude org users list [--limit N] List members
|
|
259
|
+
vat claude org users get <user-id> Get single member
|
|
260
|
+
vat claude org invites list List invitations
|
|
261
|
+
vat claude org workspaces list List API workspaces
|
|
262
|
+
vat claude org workspaces get <id> Get single workspace
|
|
263
|
+
vat claude org workspaces members list <id> Workspace members
|
|
264
|
+
vat claude org api-keys list [--status S] API key inventory
|
|
265
|
+
vat claude org usage [--from DT] [--to DT] Token usage report
|
|
266
|
+
vat claude org cost [--from DT] [--group-by F] USD cost report
|
|
267
|
+
vat claude org code-analytics [--from DATE] Claude Code metrics (YYYY-MM-DD)
|
|
268
|
+
vat claude org skills list Workspace skills (needs ANTHROPIC_API_KEY)
|
|
269
|
+
vat claude org skills install <source> Upload skill dir or ZIP to org
|
|
270
|
+
vat claude org skills delete <skill-id> Delete a skill (versions first)
|
|
271
|
+
vat claude org skills versions list <skill-id> List skill versions
|
|
272
|
+
vat claude org skills versions delete <id> <ver> Delete a skill version
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Exit codes: `0` success, `1` expected failure (stubs), `2` system error (missing key, API error).
|
|
276
|
+
|
|
277
|
+
**Skill deletion lifecycle:** The API requires all versions to be deleted before the skill itself.
|
|
278
|
+
Use `versions list` to find versions, `versions delete` each one, then `delete` the skill.
|
|
279
|
+
|
|
280
|
+
## Enterprise Skill Distribution
|
|
281
|
+
|
|
282
|
+
### Skills API (claude.ai / Console)
|
|
283
|
+
|
|
284
|
+
Skills uploaded via `POST /v1/skills` are **workspace-scoped** and **automatically available to
|
|
285
|
+
all workspace members**. There is no per-user enable/disable via the API — visibility is
|
|
286
|
+
workspace-level only. The admin UI may have additional controls not exposed in the API.
|
|
287
|
+
|
|
288
|
+
**Upload from npm package:**
|
|
289
|
+
```bash
|
|
290
|
+
# Upload all skills from a package
|
|
291
|
+
vat claude org skills install --from-npm @scope/my-skills-package@1.0.0
|
|
292
|
+
|
|
293
|
+
# Upload a single skill
|
|
294
|
+
vat claude org skills install --from-npm @scope/my-skills-package@1.0.0 --skill my-skill
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
The package must contain `dist/skills/<name>/SKILL.md` (produced by `vat skills build`).
|
|
298
|
+
If skills are in a sub-dependency, the command searches `node_modules/*/dist/skills/` too.
|
|
299
|
+
|
|
300
|
+
**Duplicate titles are rejected** — the API enforces unique `display_title` per workspace.
|
|
301
|
+
When uploading multiple skills, failures are non-fatal; partial results are reported.
|
|
302
|
+
|
|
303
|
+
### Managed Settings (Claude Code plugins)
|
|
304
|
+
|
|
305
|
+
For enterprise-wide Claude Code plugin deployment (not the Skills API), use managed settings
|
|
306
|
+
pushed via MDM (Jamf, Intune, SCCM, etc.):
|
|
307
|
+
|
|
308
|
+
| Platform | Path |
|
|
309
|
+
|---|---|
|
|
310
|
+
| macOS | `/Library/Application Support/ClaudeCode/managed-settings.json` |
|
|
311
|
+
| Linux | `/etc/claude-code/managed-settings.json` |
|
|
312
|
+
| Windows | `C:\Program Files\ClaudeCode\managed-settings.json` |
|
|
313
|
+
|
|
314
|
+
Managed settings are **highest priority** in the settings cascade — they override user settings.
|
|
315
|
+
Use this to force-enable plugins, lock down permissions, or configure organization defaults.
|
|
316
|
+
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"enabledPlugins": {
|
|
320
|
+
"my-plugin@my-marketplace": true
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Combine with `npm install -g <package>` (via IT software deployment) to install the plugin
|
|
326
|
+
binary, then managed settings to enable it across all machines.
|
|
327
|
+
|
|
328
|
+
## Not Yet Implemented
|
|
329
|
+
|
|
330
|
+
These commands exist with the correct CLI shape but return structured
|
|
331
|
+
`not-yet-implemented` stubs (exit 1). Coming in a future release:
|
|
332
|
+
|
|
333
|
+
- `org users update/remove` — role changes, offboarding
|
|
334
|
+
- `org invites create/delete` — programmatic invitations
|
|
335
|
+
- `org workspaces create/archive` — workspace lifecycle
|
|
336
|
+
- `org workspaces members add/update/remove` — workspace membership
|
|
337
|
+
- `org api-keys update` — rename keys
|
|
@@ -40,6 +40,7 @@ non-TypeScript/JavaScript projects, or cases where you need deep framework-speci
|
|
|
40
40
|
| `--target claude-web` ZIP format | `vibe-agent-toolkit:distribution` |
|
|
41
41
|
| Install/uninstall methods, enterprise deployment, Desktop vs CLI paths | `vibe-agent-toolkit:install` |
|
|
42
42
|
| `vat audit`, `--compat`, CI validation | `vibe-agent-toolkit:audit` |
|
|
43
|
+
| `vat claude org`, Admin API, org users/cost/usage/skills, ANTHROPIC_ADMIN_API_KEY | `vibe-agent-toolkit:org-admin` |
|
|
43
44
|
| VAT behaves unexpectedly, debugging VAT, testing local VAT changes, VAT_ROOT_DIR | `vibe-agent-toolkit:debugging` |
|
|
44
45
|
|
|
45
46
|
## Agent Archetypes (Quick Reference)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-agent-toolkit/vat-development-agents",
|
|
3
|
-
"version": "0.1.22
|
|
3
|
+
"version": "0.1.22",
|
|
4
4
|
"description": "VAT development agents - dogfooding the vibe-agent-toolkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -64,13 +64,13 @@
|
|
|
64
64
|
"postinstall": "vat claude plugin install --npm-postinstall || exit 0"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@vibe-agent-toolkit/agent-schema": "0.1.22
|
|
68
|
-
"@vibe-agent-toolkit/cli": "0.1.22
|
|
67
|
+
"@vibe-agent-toolkit/agent-schema": "0.1.22",
|
|
68
|
+
"@vibe-agent-toolkit/cli": "0.1.22",
|
|
69
69
|
"yaml": "^2.8.2"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.0.3",
|
|
73
|
-
"@vibe-agent-toolkit/resource-compiler": "0.1.22
|
|
73
|
+
"@vibe-agent-toolkit/resource-compiler": "0.1.22",
|
|
74
74
|
"ts-patch": "^3.2.1",
|
|
75
75
|
"typescript": "^5.7.3"
|
|
76
76
|
},
|