@soku-ai/cli 0.1.0-alpha.1 → 0.1.0-alpha.11
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/auth/device.d.ts +11 -0
- package/dist/auth/device.d.ts.map +1 -1
- package/dist/auth/device.js +17 -1
- package/dist/auth/device.js.map +1 -1
- package/dist/commands/ads.d.ts +32 -0
- package/dist/commands/ads.d.ts.map +1 -0
- package/dist/commands/ads.js +752 -0
- package/dist/commands/ads.js.map +1 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +28 -7
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/automation.d.ts +80 -0
- package/dist/commands/automation.d.ts.map +1 -0
- package/dist/commands/automation.js +213 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/brand-skill.d.ts +72 -0
- package/dist/commands/brand-skill.d.ts.map +1 -0
- package/dist/commands/brand-skill.js +351 -0
- package/dist/commands/brand-skill.js.map +1 -0
- package/dist/commands/brand.d.ts.map +1 -1
- package/dist/commands/brand.js +59 -1
- package/dist/commands/brand.js.map +1 -1
- package/dist/commands/call.d.ts.map +1 -1
- package/dist/commands/call.js +6 -3
- package/dist/commands/call.js.map +1 -1
- package/dist/commands/context.d.ts +23 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +291 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/files.d.ts +10 -0
- package/dist/commands/files.d.ts.map +1 -0
- package/dist/commands/files.js +48 -0
- package/dist/commands/files.js.map +1 -0
- package/dist/commands/generated.d.ts +24 -3
- package/dist/commands/generated.d.ts.map +1 -1
- package/dist/commands/generated.js +97 -10
- package/dist/commands/generated.js.map +1 -1
- package/dist/commands/memory.d.ts +18 -0
- package/dist/commands/memory.d.ts.map +1 -0
- package/dist/commands/memory.js +70 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +46 -2
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/seo-hosting.d.ts +107 -0
- package/dist/commands/seo-hosting.d.ts.map +1 -0
- package/dist/commands/seo-hosting.js +499 -0
- package/dist/commands/seo-hosting.js.map +1 -0
- package/dist/commands/skill.d.ts +50 -6
- package/dist/commands/skill.d.ts.map +1 -1
- package/dist/commands/skill.js +120 -56
- package/dist/commands/skill.js.map +1 -1
- package/dist/commands/update.d.ts +23 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +345 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/workspace.d.ts +4 -0
- package/dist/commands/workspace.d.ts.map +1 -0
- package/dist/commands/workspace.js +132 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/config.d.ts +5 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -7
- package/dist/config.js.map +1 -1
- package/dist/generated/capabilities.json +291 -30
- package/dist/http/client.d.ts.map +1 -1
- package/dist/http/client.js +74 -16
- package/dist/http/client.js.map +1 -1
- package/dist/index.js +35 -3
- package/dist/index.js.map +1 -1
- package/dist/output/envelope.d.ts +5 -0
- package/dist/output/envelope.d.ts.map +1 -1
- package/dist/output/envelope.js +101 -2
- package/dist/output/envelope.js.map +1 -1
- package/dist/output/unwrap.d.ts.map +1 -1
- package/dist/output/unwrap.js +18 -1
- package/dist/output/unwrap.js.map +1 -1
- package/dist/skills/unzip.d.ts +1 -1
- package/dist/skills/unzip.js +1 -1
- package/dist/update-check.d.ts +0 -1
- package/dist/update-check.d.ts.map +1 -1
- package/dist/update-check.js +4 -54
- package/dist/update-check.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +7 -4
- package/postinstall.cjs +85 -0
- package/skills/soku/SKILL.md +402 -32
- package/README.md +0 -91
package/dist/version.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,iBAAiB,CAAA;AAC9C,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,iBAAiB,CAAA;AAC9C,eAAO,MAAM,WAAW,mBAAmB,CAAA"}
|
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAA;AAC9C,MAAM,CAAC,MAAM,WAAW,GAAG,
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAA;AAC9C,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soku-ai/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
4
|
-
"description": "Soku CLI — call Soku ads/GA4 data capabilities from any AI agent or shell.",
|
|
3
|
+
"version": "0.1.0-alpha.11",
|
|
4
|
+
"description": "Soku CLI — call Soku ads/GA4/PostHog data capabilities from any AI agent or shell.",
|
|
5
5
|
"license": "Proprietary",
|
|
6
6
|
"author": "Soku",
|
|
7
7
|
"homepage": "https://soku.ai/cli",
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"ai-agent",
|
|
20
20
|
"marketing-analytics",
|
|
21
21
|
"google-ads",
|
|
22
|
-
"ga4"
|
|
22
|
+
"ga4",
|
|
23
|
+
"posthog"
|
|
23
24
|
],
|
|
24
25
|
"type": "module",
|
|
25
26
|
"bin": {
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
},
|
|
28
29
|
"files": [
|
|
29
30
|
"dist",
|
|
31
|
+
"postinstall.cjs",
|
|
30
32
|
"skills"
|
|
31
33
|
],
|
|
32
34
|
"engines": {
|
|
@@ -39,9 +41,10 @@
|
|
|
39
41
|
"scripts": {
|
|
40
42
|
"build": "tsc && mkdir -p dist/generated && cp src/generated/capabilities.json dist/generated/capabilities.json",
|
|
41
43
|
"typecheck": "tsc --noEmit",
|
|
42
|
-
"test": "tsc -p tsconfig.test.json &&
|
|
44
|
+
"test": "tsc -p tsconfig.test.json && find .test-build -name '*.test.js' -print | sort | xargs node --test",
|
|
43
45
|
"gen:capabilities": "pnpm run build && node scripts/gen-capabilities.ts",
|
|
44
46
|
"clean": "rm -rf dist .test-build",
|
|
47
|
+
"postinstall": "node postinstall.cjs",
|
|
45
48
|
"prepublishOnly": "pnpm run clean && pnpm run build"
|
|
46
49
|
},
|
|
47
50
|
"dependencies": {
|
package/postinstall.cjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* Refresh previously installed bundled Soku meta-skills after a global npm
|
|
4
|
+
* install. Business skills still update through `soku update skills`, because
|
|
5
|
+
* that path verifies catalog zip checksums and may need network access.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('node:fs')
|
|
9
|
+
const os = require('node:os')
|
|
10
|
+
const path = require('node:path')
|
|
11
|
+
|
|
12
|
+
const MANIFEST_FILE = '.soku-skills.json'
|
|
13
|
+
const SOKU_META = 'soku'
|
|
14
|
+
|
|
15
|
+
function shouldRun() {
|
|
16
|
+
return process.env.npm_config_global === 'true' || process.env.npm_config_global === '1'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function copyDir(source, dest) {
|
|
20
|
+
fs.mkdirSync(dest, { recursive: true })
|
|
21
|
+
for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
|
|
22
|
+
const from = path.join(source, entry.name)
|
|
23
|
+
const to = path.join(dest, entry.name)
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
copyDir(from, to)
|
|
26
|
+
} else if (entry.isFile()) {
|
|
27
|
+
fs.copyFileSync(from, to)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function loadManifest(baseDir) {
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(fs.readFileSync(path.join(baseDir, MANIFEST_FILE), 'utf8'))
|
|
35
|
+
} catch {
|
|
36
|
+
return {}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function hasSokuSkill(baseDir) {
|
|
41
|
+
const manifest = loadManifest(baseDir)
|
|
42
|
+
return (
|
|
43
|
+
Object.keys(manifest).length > 0 ||
|
|
44
|
+
fs.existsSync(path.join(baseDir, SOKU_META, 'SKILL.md'))
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function refreshMetaSkill(baseDir, bundledDir) {
|
|
49
|
+
if (!hasSokuSkill(baseDir)) return
|
|
50
|
+
|
|
51
|
+
const dest = path.join(baseDir, SOKU_META)
|
|
52
|
+
fs.mkdirSync(dest, { recursive: true })
|
|
53
|
+
fs.rmSync(path.join(dest, 'SKILL.md'), { force: true })
|
|
54
|
+
fs.rmSync(path.join(dest, 'references'), { recursive: true, force: true })
|
|
55
|
+
fs.copyFileSync(path.join(bundledDir, 'SKILL.md'), path.join(dest, 'SKILL.md'))
|
|
56
|
+
const referencesDir = path.join(bundledDir, 'references')
|
|
57
|
+
if (fs.existsSync(referencesDir)) {
|
|
58
|
+
copyDir(referencesDir, path.join(dest, 'references'))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const manifest = loadManifest(baseDir)
|
|
62
|
+
manifest[SOKU_META] = {
|
|
63
|
+
sha256: '',
|
|
64
|
+
installed_at: new Date().toISOString(),
|
|
65
|
+
source: 'bundled',
|
|
66
|
+
}
|
|
67
|
+
fs.writeFileSync(path.join(baseDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\n`)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function main() {
|
|
71
|
+
if (!shouldRun()) return
|
|
72
|
+
const bundledDir = path.join(__dirname, 'skills', SOKU_META)
|
|
73
|
+
if (!fs.existsSync(path.join(bundledDir, 'SKILL.md'))) return
|
|
74
|
+
|
|
75
|
+
for (const agentDir of ['.claude/skills', '.codex/skills', '.cursor/skills']) {
|
|
76
|
+
try {
|
|
77
|
+
refreshMetaSkill(path.join(os.homedir(), agentDir), bundledDir)
|
|
78
|
+
} catch {
|
|
79
|
+
// Best-effort lifecycle hook: npm install must not fail because an agent
|
|
80
|
+
// skill directory is missing, locked, or otherwise temporarily unreadable.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
main()
|
package/skills/soku/SKILL.md
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: soku
|
|
3
3
|
description: >-
|
|
4
|
-
Use when calling Soku ads/GA4 marketing-data capabilities
|
|
4
|
+
Use when calling Soku ads/GA4/PostHog marketing-data capabilities or SEO
|
|
5
|
+
Hosting domain connections from the shell —
|
|
5
6
|
running `soku auth login`, switching org/brand with `soku org use` /
|
|
6
7
|
`soku brand use`, discovering capabilities, calling a data action, routing a
|
|
7
8
|
third-party API call (Ahrefs/DataForSEO/Firecrawl/Gemini/…) through
|
|
8
|
-
`soku egress`,
|
|
9
|
+
`soku egress`, managing `soku seo-hosting connections`, managing
|
|
10
|
+
`soku automation`, using typed Meta Ads write commands, handling 401/403
|
|
11
|
+
errors, or installing/updating the Soku CLI.
|
|
9
12
|
license: Proprietary
|
|
10
13
|
metadata:
|
|
11
14
|
author: nex-ad
|
|
12
|
-
version: "0.
|
|
15
|
+
version: "0.3"
|
|
13
16
|
---
|
|
14
17
|
|
|
15
18
|
# Soku CLI
|
|
16
19
|
|
|
17
|
-
The `soku` CLI calls Soku's ads
|
|
18
|
-
preferred way for an agent to use Soku
|
|
19
|
-
host required. Output is JSON on stdout; errors are a
|
|
20
|
-
with a semantic exit code.
|
|
20
|
+
The `soku` CLI calls Soku's ads, GA4, PostHog, SEO Hosting, and Automation
|
|
21
|
+
capabilities over HTTP. It is the preferred way for an agent to use Soku from
|
|
22
|
+
any shell, with no MCP host required. Output is JSON on stdout; errors are a
|
|
23
|
+
JSON envelope on stderr with a semantic exit code.
|
|
21
24
|
|
|
22
25
|
## Output & exit codes
|
|
23
26
|
|
|
@@ -36,6 +39,10 @@ Every command prints JSON. When piped (non-TTY) success is
|
|
|
36
39
|
|
|
37
40
|
`soku` authenticates once per machine with a long-lived, **org-agnostic** session
|
|
38
41
|
token. The org and brand are chosen at runtime (see Workspace), not at login.
|
|
42
|
+
By default, `soku auth login` requests every resource bundle known to the CLI so
|
|
43
|
+
agents can use reads, approved writes, SEO Hosting, automations, Context Hub,
|
|
44
|
+
asset publishing, and Brand Skills without re-authenticating. Only pass
|
|
45
|
+
`--resource` when the user explicitly wants a narrower token.
|
|
39
46
|
|
|
40
47
|
### Agent path (recommended): non-blocking split-flow
|
|
41
48
|
|
|
@@ -89,19 +96,46 @@ soku org list # organizations you belong to
|
|
|
89
96
|
soku org use <slug|id> # set active org (id, slug, or name; clears a now-mismatched brand)
|
|
90
97
|
soku brand list # brands in the active org
|
|
91
98
|
soku brand use <slug|id> # id, slug, or name
|
|
99
|
+
soku workspace status # show the active org/brand and whether it is ready
|
|
100
|
+
soku workspace resolve <brand> # inspect accessible brand matches across orgs
|
|
101
|
+
soku workspace use-brand <brand> # set org + brand together when the match is unique
|
|
92
102
|
```
|
|
93
103
|
|
|
94
104
|
Env overrides for one-off invocations: `SOKU_ORG_ID`, `SOKU_BRAND_ID`.
|
|
95
105
|
|
|
106
|
+
Do not infer Soku workspace state from the current shell directory. The working
|
|
107
|
+
directory may contain unrelated README/AGENTS/context files from the user's local
|
|
108
|
+
project. Start with `soku workspace status`; if the target brand is unknown, use
|
|
109
|
+
`soku workspace resolve <brand>` and then `soku workspace use-brand <brand>`.
|
|
110
|
+
|
|
111
|
+
## Brand memory
|
|
112
|
+
|
|
113
|
+
Memory is scoped to the active Soku workspace, not to the local shell directory.
|
|
114
|
+
After `soku workspace status` is ready, these commands read memory for the
|
|
115
|
+
current brand only:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
soku memory list
|
|
119
|
+
soku memory search "policy 2026-05-31"
|
|
120
|
+
soku memory get reference noiz-policy-event
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Use brand memory as background, hypotheses, and investigation leads. Do not
|
|
124
|
+
treat a memory note as a verified data fact unless this turn also confirms it
|
|
125
|
+
with data actions, change history, billing evidence, or another authoritative
|
|
126
|
+
source. In reports, label memory-derived context separately from data-confirmed
|
|
127
|
+
findings.
|
|
128
|
+
|
|
96
129
|
## Calling capabilities (discover with --help, then run)
|
|
97
130
|
|
|
98
131
|
Each data capability is a typed sub-command under its namespace. Discover and
|
|
99
132
|
inspect them with `--help` — never guess action names or flags.
|
|
100
133
|
|
|
101
134
|
```bash
|
|
102
|
-
soku resources list # what's granted (e.g. data-infra)
|
|
103
|
-
soku --help # namespaces: ads, ga4, …
|
|
135
|
+
soku resources list # what's granted (e.g. data-infra, seo-hosting, automation)
|
|
136
|
+
soku --help # namespaces: ads, ga4, posthog, …
|
|
104
137
|
soku ads --help # actions in the ads namespace
|
|
138
|
+
soku posthog --help # customer PostHog read actions
|
|
105
139
|
soku ads query-single-dimension --help # flags, types, and usage for one action
|
|
106
140
|
|
|
107
141
|
soku ads list-ad-accounts --platform google
|
|
@@ -110,8 +144,57 @@ soku ads query-single-dimension --account-id 123 --dimension campaign \
|
|
|
110
144
|
```
|
|
111
145
|
|
|
112
146
|
`<command> --help` is authoritative for valid flags, required vs optional, types,
|
|
113
|
-
and usage. Read it before invoking an unfamiliar action.
|
|
114
|
-
|
|
147
|
+
and usage. Read it before invoking an unfamiliar action. Typed command names use
|
|
148
|
+
kebab-case (`soku ads query-single-dimension`); raw `soku call` action names use
|
|
149
|
+
registry snake_case (`soku call ads query_single_dimension`). Object/list flags
|
|
150
|
+
take a JSON string, e.g. `--filters '{"campaign_id":["123"]}'`.
|
|
151
|
+
|
|
152
|
+
### Google Ads GAQL fallback
|
|
153
|
+
|
|
154
|
+
Prefer cached ads analytics first:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
soku ads list-dimensions --platform google --account-id 123
|
|
158
|
+
soku ads query-single-dimension --account-id 123 --dimension campaign ...
|
|
159
|
+
soku ads query-multi-dimension --account-id 123 --dimensions '["campaign","device"]' ...
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Use GAQL only when cached query actions cannot expose the Google-native fields
|
|
163
|
+
or segment combination you need:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
soku ads get-resource-metadata --platform google --account-id 123 --resource-name campaign
|
|
167
|
+
soku ads gaql-search --platform google --account-id 123 \
|
|
168
|
+
--dimensions '["date","campaign"]' --metrics '["cost","clicks"]' --limit 20
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Do not write full `SELECT ... FROM ...` GAQL SQL. `gaql-search` takes structured
|
|
172
|
+
`dimensions`, `metrics`, `filters`, `date_range`, `order_by`, and `limit`; the
|
|
173
|
+
server translates those into real GAQL. For the same action through the raw
|
|
174
|
+
escape hatch, use snake_case: `soku call ads gaql_search --payload '{...}'`.
|
|
175
|
+
|
|
176
|
+
### PostHog customer analytics
|
|
177
|
+
|
|
178
|
+
PostHog data uses the same backend MCP forwarding gateway as the sandbox agent.
|
|
179
|
+
Start by listing the current brand's granted projects, then inspect the live
|
|
180
|
+
tool menu, then run an allowlisted read tool. Do not ask the user for a project
|
|
181
|
+
id before listing projects.
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
soku posthog list-projects
|
|
185
|
+
soku posthog list-tools --project-id 12345
|
|
186
|
+
soku posthog query --project-id 12345 --tool execute-sql \
|
|
187
|
+
--arguments '{"query":"SELECT count() FROM events WHERE event = '\''$pageview'\''"}'
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Use `read-data-schema` before writing HogQL if field names are unclear:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
soku posthog query --project-id 12345 --tool read-data-schema --arguments '{}'
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The CLI default read surface does not expose `posthog/request_change`; writes and
|
|
197
|
+
unvetted PostHog MCP tools remain outside the generated command tree.
|
|
115
198
|
|
|
116
199
|
### Raw escape hatch
|
|
117
200
|
|
|
@@ -122,18 +205,284 @@ a newer action than this CLI version ships:
|
|
|
122
205
|
```bash
|
|
123
206
|
soku call ads list_ad_accounts -p platform=google
|
|
124
207
|
soku call ads query_single_dimension --payload '{"account_id":"123","dimension":"campaign"}'
|
|
208
|
+
soku call posthog query --payload '{"project_id":"12345","tool":"execute-sql","arguments":{"query":"SELECT count() FROM events"}}'
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Meta Ads typed commands
|
|
212
|
+
|
|
213
|
+
Meta Ads campaign-tree and creative workflows have an ergonomic typed command
|
|
214
|
+
tree under `soku ads meta`. Use these commands before the raw escape hatch; they
|
|
215
|
+
wrap the same backend actions but expose stable, platform-specific flags and
|
|
216
|
+
client-side validation. Always inspect the exact command help before invoking a
|
|
217
|
+
new verb:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
soku ads meta --help
|
|
221
|
+
soku ads meta campaign create --help
|
|
222
|
+
soku ads meta asset upload-images --help
|
|
223
|
+
soku ads meta creative create --help
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Use the normal agent login before Meta write workflows:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
soku auth login --no-wait
|
|
230
|
+
soku workspace status
|
|
231
|
+
soku ads list-ad-accounts --platform meta
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
If you are intentionally using a restricted token, it must include
|
|
235
|
+
`data-infra,ads-write` for this workflow.
|
|
236
|
+
|
|
237
|
+
Useful read helpers:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
soku ads meta account pages --account-id <meta_account_id>
|
|
241
|
+
soku ads meta campaign get --account-id <meta_account_id> --campaign-id <campaign_id>
|
|
242
|
+
soku ads meta ad get --account-id <meta_account_id> --ad-id <ad_id>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Asset upload is a direct support action: it mutates Meta's asset library but
|
|
246
|
+
does not change delivery and does not require a review summary. Local image
|
|
247
|
+
files are read by the CLI and sent as bytes; public URLs are passed as URLs.
|
|
248
|
+
The result includes `image_hash` values for creative creation.
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
soku ads meta asset upload-images --account-id <meta_account_id> ./hero.png ./square.jpg
|
|
252
|
+
soku ads meta asset upload-images --account-id <meta_account_id> \
|
|
253
|
+
--url https://example.com/hero.png --name-prefix launch
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Common single-object write flow. Campaign and ad creation land paused; other
|
|
257
|
+
delivery-changing writes are review-gated. Every gated command requires
|
|
258
|
+
`--summary`, returns a review id, and executes only after human approval.
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
soku ads meta campaign create \
|
|
262
|
+
--account-id <meta_account_id> \
|
|
263
|
+
--name "Launch Test" \
|
|
264
|
+
--objective OUTCOME_TRAFFIC \
|
|
265
|
+
--summary "Create paused Meta traffic campaign Launch Test"
|
|
266
|
+
|
|
267
|
+
soku ads meta adset create \
|
|
268
|
+
--account-id <meta_account_id> \
|
|
269
|
+
--campaign-id <campaign_id> \
|
|
270
|
+
--name "US Prospecting" \
|
|
271
|
+
--optimization-goal LINK_CLICKS \
|
|
272
|
+
--billing-event IMPRESSIONS \
|
|
273
|
+
-p targeting='{"geo_locations":{"countries":["US"]}}' \
|
|
274
|
+
--summary "Create paused Meta ad set US Prospecting"
|
|
275
|
+
|
|
276
|
+
soku ads meta creative create \
|
|
277
|
+
--account-id <meta_account_id> \
|
|
278
|
+
--name "Hero image creative" \
|
|
279
|
+
--page-id <page_id> \
|
|
280
|
+
--image-hash <image_hash> \
|
|
281
|
+
--message "Primary text" \
|
|
282
|
+
--headline "Headline" \
|
|
283
|
+
--link https://example.com \
|
|
284
|
+
--call-to-action-type LEARN_MORE \
|
|
285
|
+
--summary "Create Meta image creative for Launch Test"
|
|
286
|
+
|
|
287
|
+
soku ads meta ad create \
|
|
288
|
+
--account-id <meta_account_id> \
|
|
289
|
+
--adset-id <adset_id> \
|
|
290
|
+
--name "Hero image ad" \
|
|
291
|
+
--creative-id <creative_id> \
|
|
292
|
+
--summary "Create paused Meta ad Hero image ad"
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Status controls exist at all three delivery levels:
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
soku ads meta campaign activate --campaign-id <campaign_id> --account-id <meta_account_id> --summary "Activate campaign"
|
|
299
|
+
soku ads meta adset pause --adset-id <adset_id> --account-id <meta_account_id> --summary "Pause ad set"
|
|
300
|
+
soku ads meta ad pause --ad-id <ad_id> --account-id <meta_account_id> --summary "Pause ad"
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Bulk commands are intentionally one layer at a time. Each command takes a JSON
|
|
304
|
+
array file, and each item must be an object with a unique non-empty
|
|
305
|
+
`client_ref`. The CLI injects `platform=meta` and the `--account-id`; item fields
|
|
306
|
+
mirror the corresponding raw action payload (`create_campaign`,
|
|
307
|
+
`create_adset`, `create_ad_creative`, or `create_ad`). Bulk approvals execute
|
|
308
|
+
asynchronously after the human approves the review; poll with
|
|
309
|
+
`soku review show <review_id>`.
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
cat > campaigns.json <<'JSON'
|
|
313
|
+
[
|
|
314
|
+
{
|
|
315
|
+
"client_ref": "campaign-us-traffic",
|
|
316
|
+
"name": "US Traffic Test",
|
|
317
|
+
"objective": "OUTCOME_TRAFFIC"
|
|
318
|
+
}
|
|
319
|
+
]
|
|
320
|
+
JSON
|
|
321
|
+
|
|
322
|
+
soku ads meta campaign bulk-create \
|
|
323
|
+
--account-id <meta_account_id> \
|
|
324
|
+
--items-file campaigns.json \
|
|
325
|
+
--summary "Bulk-create paused Meta campaigns for launch test"
|
|
326
|
+
|
|
327
|
+
soku ads meta adset bulk-create --account-id <meta_account_id> --items-file adsets.json --summary "Bulk-create Meta ad sets"
|
|
328
|
+
soku ads meta creative bulk-create --account-id <meta_account_id> --items-file creatives.json --summary "Bulk-create Meta creatives"
|
|
329
|
+
soku ads meta ad bulk-create --account-id <meta_account_id> --items-file ads.json --summary "Bulk-create paused Meta ads"
|
|
125
330
|
```
|
|
126
331
|
|
|
332
|
+
Use `soku call ads <raw_action>` only when the Meta action is not exposed in the
|
|
333
|
+
typed tree, such as some audience, pixel, lead form, label, rule, targeting, or
|
|
334
|
+
live-insights operations.
|
|
335
|
+
|
|
336
|
+
## Automations
|
|
337
|
+
|
|
338
|
+
Use `soku automation` to manage automations for the active brand. Default agent
|
|
339
|
+
login includes the `automation` resource. If you are intentionally using a
|
|
340
|
+
restricted token, include `automation` explicitly:
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# Restricted-token examples only:
|
|
344
|
+
soku auth login --resource automation
|
|
345
|
+
soku auth login --resource data-infra,automation
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
The workspace must be ready before any automation call:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
soku workspace status
|
|
352
|
+
soku org use <slug|id>
|
|
353
|
+
soku brand use <slug|id>
|
|
354
|
+
soku resources list
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Commands:
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
soku automation list
|
|
361
|
+
soku automation create --name "Fast check" --prompt "Check account health" --cron "* * * * *" --timezone UTC
|
|
362
|
+
soku automation trigger <automation_id>
|
|
363
|
+
soku automation runs <automation_id>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
`create` requires exactly one schedule option:
|
|
367
|
+
|
|
368
|
+
- `--cron <expr>` with optional `--timezone <iana>` (default `UTC`).
|
|
369
|
+
- `--interval-seconds <seconds>` for interval schedules; must be at least
|
|
370
|
+
`3600` and divisible by `60`.
|
|
371
|
+
- `--once-at <iso>` for a one-time UTC instant.
|
|
372
|
+
|
|
373
|
+
`runs` shows run status and a browser link when a conversation exists. The CLI
|
|
374
|
+
does not read conversation content; open the printed link in Studio to inspect
|
|
375
|
+
the actual chat. For local development links, set `SOKU_WEB_BASE`, for example:
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
SOKU_WEB_BASE=http://127.0.0.1:47627 soku automation runs <automation_id>
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## SEO Hosting domain connections
|
|
382
|
+
|
|
383
|
+
Use `soku seo-hosting` to manage SEO Hosting for the active brand. Default agent
|
|
384
|
+
login includes the `seo-hosting` resource. If you are intentionally using a
|
|
385
|
+
restricted token, include `seo-hosting` explicitly:
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# Restricted-token examples only:
|
|
389
|
+
soku auth login --resource seo-hosting
|
|
390
|
+
soku auth login --resource data-infra,seo-hosting
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
The workspace must be ready before any connection call:
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
soku workspace status
|
|
397
|
+
soku org use <slug|id>
|
|
398
|
+
soku brand use <slug|id>
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Posts
|
|
402
|
+
|
|
403
|
+
Use typed `pages` commands for the same SEO Hosting content actions exposed to
|
|
404
|
+
runtime agents through `seo_hosting/*`. SEO Hosting pages are **complete HTML
|
|
405
|
+
documents** (not Markdown) served as owned-media web pages on the brand's
|
|
406
|
+
connected domain; they are identified by `section` + `slug` (there are no post
|
|
407
|
+
ids). They are not social posts.
|
|
408
|
+
|
|
409
|
+
Always check status first:
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
soku seo-hosting status
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
`status` shows each connected domain, whether it is `live`, and which sections it
|
|
416
|
+
serves. If no domain is live, do not publish yet; connect or fix a domain first.
|
|
417
|
+
When hosting is live:
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
soku seo-hosting pages list --section blog --status draft
|
|
421
|
+
soku seo-hosting pages put --section blog --slug how-to --title "How to ..." --html-file page.html
|
|
422
|
+
soku seo-hosting pages publish --section blog --slug how-to
|
|
423
|
+
soku seo-hosting pages unpublish --section blog --slug how-to
|
|
424
|
+
soku seo-hosting pages delete --section blog --slug how-to --confirm
|
|
425
|
+
soku seo-hosting pages upload-asset --path blog/how-to/hero.png --file ./hero.png
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
`put` creates or overwrites a page as a **draft** and requires `--section`,
|
|
429
|
+
`--slug`, `--title`, and exactly one HTML source: `--html`, `--html-file`, or
|
|
430
|
+
`--html-stdin`. Optional metadata flags are `--description`, `--template`, and
|
|
431
|
+
`--seo '<json object>'`. Reference images / CSS / fonts by the absolute URL
|
|
432
|
+
returned from `pages upload-asset` (no custom JavaScript — HTML + CSS only).
|
|
433
|
+
|
|
434
|
+
`publish` runs the validation gate (no `<script>` / inline JS) and
|
|
435
|
+
makes the page live once a domain serves its section; it also prints advisory
|
|
436
|
+
`Link warnings` for dead internal links (these do not block publishing — fix the
|
|
437
|
+
links and re-publish). `unpublish` reverts it to draft. Writes run immediately
|
|
438
|
+
(no-review), so confirm intent with the user before publishing or deleting.
|
|
439
|
+
|
|
440
|
+
### Domain connections
|
|
441
|
+
|
|
442
|
+
Connection commands:
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
soku seo-hosting connections list
|
|
446
|
+
soku seo-hosting connections connect-cname --hostname blog.example.com
|
|
447
|
+
soku seo-hosting connections verify <connection_id>
|
|
448
|
+
soku seo-hosting connections disconnect <connection_id> --confirm
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Cloudflare Worker reverse proxy setup runs a probe before provisioning. Use it
|
|
452
|
+
when the customer's root or existing hostname is already on Cloudflare and SEO
|
|
453
|
+
Hosting needs to mount sections such as `/blog`, `/use-cases`, or
|
|
454
|
+
`/alternatives`:
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
soku seo-hosting connections probe --hostname example.com --sections blog,use-cases
|
|
458
|
+
soku seo-hosting connections connect-worker --hostname example.com \
|
|
459
|
+
--sections blog,use-cases --cf-token-env CLOUDFLARE_API_TOKEN
|
|
460
|
+
printf %s "$CLOUDFLARE_API_TOKEN" | soku seo-hosting connections connect-worker \
|
|
461
|
+
--hostname example.com --sections blog --cf-token-stdin
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
Allowed sections are `blog`, `use-cases`, and `alternatives`; omitted sections
|
|
465
|
+
default to `blog`. If the probe reports existing mounted content, add
|
|
466
|
+
`--accept-conflicts` only after the user confirms SEO Hosting may shadow those
|
|
467
|
+
paths. If the hostname serves its own Next.js assets, add
|
|
468
|
+
`--accept-next-assets-warning` only after confirming `/_next/static/*` may route
|
|
469
|
+
through the Worker.
|
|
470
|
+
|
|
471
|
+
Do not pass Cloudflare API tokens as literal argv values or print them. Use
|
|
472
|
+
`--cf-token-env <ENV_NAME>` or `--cf-token-stdin` exactly once. Vercel OAuth
|
|
473
|
+
domain connections are not exposed in the CLI yet; use the Studio web settings
|
|
474
|
+
for Vercel-backed domains.
|
|
475
|
+
|
|
127
476
|
## Write actions (human approval required)
|
|
128
477
|
|
|
129
|
-
Some actions mutate state
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
a
|
|
478
|
+
Some actions mutate state and are **review-gated**. Prefer typed commands when
|
|
479
|
+
they exist (`soku ads meta ...`, `soku ads google ...`). Use `soku call` for raw
|
|
480
|
+
actions that are not exposed as typed commands. Review-gated commands do NOT
|
|
481
|
+
execute immediately; they return a review that a human approves.
|
|
133
482
|
|
|
134
483
|
```bash
|
|
135
484
|
soku call ads create_conversion_group --summary "create group: qualified leads" -p name="Qualified leads"
|
|
136
|
-
# → {"ok":true,"data":{"status":"pending_review","
|
|
485
|
+
# → {"ok":true,"data":{"status":"pending_review","review_id":"<id>","summary":"..."}}
|
|
137
486
|
|
|
138
487
|
soku review list # see pending reviews
|
|
139
488
|
soku review show <id> # full payload + (after approval) result
|
|
@@ -141,15 +490,16 @@ soku review approve <id> # a human approves → the action executes now
|
|
|
141
490
|
soku review deny <id> --feedback "wrong account"
|
|
142
491
|
```
|
|
143
492
|
|
|
144
|
-
- The write resource must be granted to the session
|
|
145
|
-
`
|
|
146
|
-
`soku
|
|
493
|
+
- The write resource must be granted to the session. Default login includes
|
|
494
|
+
`conversion-groups-write`; restricted tokens must include it explicitly, for
|
|
495
|
+
example `soku auth login --resource data-infra,conversion-groups-write`.
|
|
496
|
+
Without it, `soku call` returns 403.
|
|
147
497
|
- Approval is **single-use**: one review = one execution. Approving an already
|
|
148
498
|
decided review is a no-op that returns the existing result.
|
|
149
499
|
- Do NOT loop `soku review approve` expecting retries; a failed approval is
|
|
150
500
|
terminal — create a fresh `soku call` to try again.
|
|
151
|
-
- As an agent: surface the `
|
|
152
|
-
|
|
501
|
+
- As an agent: surface the `review_id` + summary to the user and let THEM run
|
|
502
|
+
`soku review approve`. Do not approve on the user's behalf.
|
|
153
503
|
|
|
154
504
|
## Third-party APIs (egress)
|
|
155
505
|
|
|
@@ -180,18 +530,25 @@ returned verbatim on stdout.
|
|
|
180
530
|
## Installing / updating the skill
|
|
181
531
|
|
|
182
532
|
```bash
|
|
183
|
-
soku update
|
|
533
|
+
soku update status # show CLI + installed skill update status
|
|
534
|
+
soku update skills # refresh this meta-skill and installed business skills
|
|
535
|
+
soku update cli # install the latest CLI from npm
|
|
184
536
|
soku skill install # this meta-skill into .claude / .codex / .cursor (project)
|
|
185
537
|
soku skill install --global # into ~/.claude, ~/.codex, ~/.cursor
|
|
186
538
|
soku skill install --agent claude --global
|
|
187
539
|
```
|
|
188
540
|
|
|
189
|
-
|
|
190
|
-
|
|
541
|
+
Normal `soku` commands schedule a background refresh for installed Soku-managed
|
|
542
|
+
skills at most once every 24 hours. Set `SOKU_NO_SKILL_AUTO_UPDATE=1` to disable
|
|
543
|
+
skill auto updates, or `SOKU_UPDATE_INTERVAL_HOURS=<n>` to change the interval.
|
|
191
544
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
545
|
+
The CLI binary itself is advisory by default. To opt into automatic npm CLI
|
|
546
|
+
updates, set `SOKU_AUTO_UPDATE_CLI=1`; otherwise run `soku update cli` when
|
|
547
|
+
`soku update status` shows a newer version.
|
|
548
|
+
|
|
549
|
+
A global `npm i -g @soku-ai/cli` refreshes this already-installed global
|
|
550
|
+
meta-skill after npm finishes installing. It does not install new skills and it
|
|
551
|
+
does not update project-local skills.
|
|
195
552
|
|
|
196
553
|
## Installing business skills (account audits, Google Ads, reports, …)
|
|
197
554
|
|
|
@@ -205,10 +562,21 @@ soku skill list # browse the catalog
|
|
|
205
562
|
soku skill install account-audit # install one (into soku-account-audit/)
|
|
206
563
|
soku skill install ads-report google-ads
|
|
207
564
|
soku skill install --all # install everything
|
|
208
|
-
soku skill
|
|
565
|
+
soku skill status # what's installed locally
|
|
566
|
+
soku skill list-installed # same as status
|
|
209
567
|
soku skill remove account-audit
|
|
210
568
|
```
|
|
211
569
|
|
|
570
|
+
Catalog slugs are used for install/remove commands (`ads-report`). Installed AI
|
|
571
|
+
client skill names are Soku-prefixed (`soku-ads-report`). When asking an agent to
|
|
572
|
+
run an installed business skill, write `use @soku-ads-report skill`, not
|
|
573
|
+
`@ads-report`.
|
|
574
|
+
|
|
575
|
+
Business skill updates are detected from `.soku-skills.json`: for each installed
|
|
576
|
+
catalog slug, Soku compares local `version`, `sha256`, and `source` against the
|
|
577
|
+
latest catalog `index.json`. A changed version, changed hash, or old source is
|
|
578
|
+
treated as an update; missing catalog entries are reported but not deleted.
|
|
579
|
+
|
|
212
580
|
Each installed skill carries a "Running this skill with the Soku CLI" section
|
|
213
581
|
(its data actions mapped to `soku call`, its third-party APIs to `soku egress`),
|
|
214
582
|
so it runs through this same CLI — no in-sandbox tools, no local API keys.
|
|
@@ -217,9 +585,11 @@ so it runs through this same CLI — no in-sandbox tools, no local API keys.
|
|
|
217
585
|
|
|
218
586
|
- Never print the access token (it grants account access). Prefer `SOKU_TOKEN`
|
|
219
587
|
for CI rather than echoing it.
|
|
220
|
-
- Reads (`data-infra`) run directly.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
588
|
+
- Reads (`data-infra`) run directly. Review-gated writes, whether invoked with
|
|
589
|
+
typed commands or `soku call`, create a pending review and only
|
|
590
|
+
`soku review approve` (a human action) executes them. Direct support writes
|
|
591
|
+
such as Meta image upload or SEO Hosting page writes execute immediately, so
|
|
592
|
+
confirm user intent before running them. Don't approve on the user's behalf,
|
|
593
|
+
and don't assume a `--yes`-style bypass exists — there isn't one.
|
|
224
594
|
- Pass user-provided values as separate argv elements (the `-p key=value` form),
|
|
225
595
|
never by string-concatenating them into a shell command.
|