outrank-cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -48,7 +48,7 @@ This repo currently targets the agent endpoints that already exist in `outrank`:
48
48
  - `products linking target-config get|update`
49
49
  - `products linking targets list|add-manual|upsert|clear-customizations|delete`
50
50
  - `products backlinks get|update|credits|earned|unverified|check-removal|reverify|subscription|subscribe-quote`
51
- - `keywords list|get|export|generation-status|add|suggest|generate|reschedule|bulk-reschedule|delete|bulk-delete`
51
+ - `keywords list|get|export|generation-status|add|update|suggest|generate|bulk-reschedule|delete|bulk-delete`
52
52
  - `articles list|get|get-content|update|update-content|replace|bulk-replace|upload-image|upload-featured-image|retry-publish|delete|precreate|generate`
53
53
  - `subscription status`
54
54
  - `usage stats`
@@ -97,6 +97,7 @@ outrank-cli auth status
97
97
  outrank-cli auth whoami
98
98
  outrank-cli products list --limit 20
99
99
  outrank-cli keywords list --product 00000000-0000-0000-0000-000000000000 --scope all
100
+ outrank-cli keywords list --product 00000000-0000-0000-0000-000000000000 --scope scheduled --q "best seo tools"
100
101
  outrank-cli keywords generation-status --product 00000000-0000-0000-0000-000000000000
101
102
  outrank-cli articles list --product 00000000-0000-0000-0000-000000000000 --status published
102
103
  outrank-cli articles get 00000000-0000-0000-0000-000000000000
@@ -152,9 +153,10 @@ outrank-cli products integrations test 00000000-0000-0000-0000-000000000000 1111
152
153
  outrank-cli keywords suggest --product 00000000-0000-0000-0000-000000000000 --theme "email marketing"
153
154
  outrank-cli keywords generate --product 00000000-0000-0000-0000-000000000000 --count 10 --source both
154
155
  outrank-cli keywords add --product 00000000-0000-0000-0000-000000000000 --json-file ./keywords.json
156
+ outrank-cli keywords update 00000000-0000-0000-0000-000000000000 --json '{"instructions":"Write for beginners and include a step-by-step setup section"}'
155
157
  outrank-cli keywords export --product 00000000-0000-0000-0000-000000000000
156
158
  outrank-cli products create --json-file ./product.json
157
- # products create now auto-queues the initial ~30-day keyword plan; poll with keywords generation-status / keywords list
159
+ # products create auto-queues the initial ~30-day keyword plan; poll with keywords generation-status / keywords list
158
160
  outrank-cli billing portal-url
159
161
  outrank-cli products update 00000000-0000-0000-0000-000000000000 --json '{"daily_article_count":2}'
160
162
  outrank-cli products output-settings update 00000000-0000-0000-0000-000000000000 --json-file ./output-settings.json
@@ -188,7 +190,7 @@ outrank-cli products backlinks check-removal 00000000-0000-0000-0000-00000000000
188
190
  outrank-cli products backlinks reverify 00000000-0000-0000-0000-000000000000 11111111-1111-1111-1111-111111111111
189
191
  outrank-cli products backlinks subscription 00000000-0000-0000-0000-000000000000
190
192
  outrank-cli products backlinks subscribe-quote 00000000-0000-0000-0000-000000000000 --plan premium
191
- outrank-cli keywords reschedule 00000000-0000-0000-0000-000000000000 --scheduled-for 2026-05-20
193
+ outrank-cli keywords update 00000000-0000-0000-0000-000000000000 --json '{"scheduled_for":"2026-05-20"}'
192
194
  outrank-cli billing purchase-products quote --additional-products 2
193
195
  ```
194
196
 
@@ -272,13 +274,22 @@ Example payload:
272
274
  ## Keyword mutation rules
273
275
 
274
276
  - Run `outrank-cli keywords generation-status --product <product-id>` before keyword writes when you are not sure the product is writable.
275
- - `keywords generate` now mirrors the dashboard Generate Keywords flow. Ask the human how many keywords to generate before calling it if they did not specify a count.
277
+ - `keywords generate` mirrors the dashboard Generate Keywords flow. Ask the human how many keywords to generate before calling it if they did not specify a count.
276
278
  - The allowed generation count is 5-30, but the real upper bound depends on free scheduler slots. Check `keywords generation-status` first when you need the current capacity.
277
279
  - Stored keywords are read-only inventory. They can be promoted into the plan with `keywords add`, but they cannot be deleted directly.
278
280
  - Scheduled keywords with created or pre-created articles are read-only.
279
281
  - Keywords in `generating_article` are read-only until generation finishes.
280
282
  - Past keywords are read-only except past `scheduled` or `disabled` keywords without an article, which can still be rescheduled.
281
283
  - If the main subscription is `past_due`, keyword mutations are blocked and reads still work.
284
+ - `keywords list` defaults to planner-first ordering for scheduled results, so page 1 prioritizes upcoming scheduled items before past ones.
285
+ - Use `keywords list --product <product-id> --scope scheduled --q "<keyword>"` when looking for one planner keyword by text. If `next_offset` is not `null`, keep paging before claiming the keyword is absent.
286
+ - Keyword records return top-level `article_type`, `article_subtype`, `expected_length`, and label fields. Read those from the keyword itself when answering article-type or expected-length questions; do not look in product output-settings for per-keyword length.
287
+ - Use `keywords update <keyword-id> --json '{"instructions":"..."}'` to add or change per-keyword instructions after creation. This matches the dashboard flow, which creates the keyword first and updates the brief afterward.
288
+ - Use `keywords update <keyword-id> --json '{"quality_questions":[{"id":"...","question":"...","answer":"..."}]}'` to answer or replace the keyword's quality questions through the same PATCH route.
289
+ - Use `keywords update <keyword-id> --json '{"scheduled_for":"YYYY-MM-DD","instructions":"..."}'` when you need to change the date and brief in one PATCH request.
290
+ - Use `keywords update <keyword-id> --json '{"scheduled_for":"YYYY-MM-DD"}'` for date-only rescheduling too; there is no separate reschedule command.
291
+ - `keywords get <keyword-id>` returns `article_type_options`, which lists the valid dropdown values for `article_type`, `article_subtype`, and `expected_length`.
292
+ - Use `keywords update --json '{"article_type":"guide","article_subtype":"explainer","expected_length":"long"}'` to mirror the scheduler card's "Article Type Settings" modal. The API rejects values outside the returned option lists.
282
293
 
283
294
  ## Article behavior notes
284
295
 
@@ -286,7 +297,10 @@ Example payload:
286
297
  - Featured image can be updated either by hosted URL through `articles update --json '{"image_url":"..."}'` or by local-file upload through `articles upload-featured-image`.
287
298
  - In-content images can be uploaded from a local file with `articles upload-image`; the command returns the hosted URL plus generated alt text so the agent can insert or replace the markdown image reference.
288
299
  - Per-article instructions are stored on the linked scheduled keyword, so `articles update --json '{"instructions":"..."}'` only works for articles that still have a linked planner keyword.
289
- - `articles update --json '{"status":"published"}'` now attempts a real publish through the product's active integration for eligible attached articles; it is not just a local status flip.
300
+ - `articles get <article-id>` returns `article_type_options`, which lists the valid dropdown values for `article_type`, `article_subtype`, and `expected_length`.
301
+ - Article records with a linked scheduled keyword also return top-level `article_type`, `article_subtype`, `expected_length`, and label fields for direct reads.
302
+ - Use `articles update --json '{"article_type":"guide","article_subtype":"comparison","expected_length":"long"}'` to mirror the dashboard's "Article Type Settings" modal. The API rejects values outside the returned option lists.
303
+ - `articles update --json '{"status":"published"}'` attempts a real publish through the product's active integration for eligible attached articles; it is not just a local status flip.
290
304
  - Slug is returned for read-only reference but cannot be changed through the agent API.
291
305
  - `articles generate <keyword-id>` is only valid for scheduled keywords due today; it mirrors the dashboard's create-and-publish action.
292
306
  - `articles precreate <keyword-id>` is only valid for eligible future scheduled keywords, is unavailable on trial subscriptions, and should be polled through the keyword state afterward.
@@ -337,7 +351,7 @@ Current scope note:
337
351
 
338
352
  - Webhook, Ghost, Shopify, Webflow, and Wix support direct validate/create/update/test. Framer supports validate, provider-specific discovery, create, and test for the newer Server API flow. WordPress Plugin supports prepare plus validate/create/update/test. Next.js Blog supports one-step create plus the shared list|get|delete surface, returning a one-time API key on create. WordPress.com supports OAuth connect plus poll, then the shared list|get|delete surface. Notion supports OAuth connect plus poll, provider-specific database/schema discovery, then update/test on the saved row.
339
353
  - V2 products are intended to keep one publishing integration. If `list` returns multiple rows, that usually means legacy V1 residue and stale rows should be reviewed and deleted.
340
- - Backlink exchange management now covers configuration, status reads, earned/unverified review queues, and reverification actions. Purchasing or changing backlink add-ons still requires the dashboard checkout flow.
354
+ - Backlink exchange management covers configuration, status reads, earned/unverified review queues, and reverification actions. Purchasing or changing backlink add-ons still requires the dashboard checkout flow.
341
355
  - Other providers are still mostly read/delete only while create, update, test, and provider-specific discovery are added one by one.
342
356
 
343
357
  ## Custom API target (advanced)
package/SKILL.md CHANGED
@@ -1,53 +1,53 @@
1
- ---
2
- name: outrank
1
+ ---
2
+ name: outrank
3
3
  description: Drive the Outrank agent API from the terminal via outrank-cli. Use when the user asks to list/create/update Outrank products, inspect or manage publishing integrations, inspect or manage keyword plans, inspect or edit articles, manage article settings, target audiences, competitors, Google Search Console connections, internal linking configuration, or quote/buy product slots. Requires outrank-cli on PATH and an Outrank API key (env OUTRANK_API_KEY or stored via auth login).
4
- ---
5
-
6
- # Outrank Skill
7
-
8
- Use `outrank-cli` to drive Outrank from the terminal. The CLI is JSON-first and every command returns `agent_guidance`, so read that field after each step and let it steer the next call.
9
-
4
+ ---
5
+
6
+ # Outrank Skill
7
+
8
+ Use `outrank-cli` to drive Outrank from the terminal. The CLI is JSON-first and every command returns `agent_guidance`, so read that field after each step and let it steer the next call.
9
+
10
10
  In human-facing responses, call `products get` / `products update` the product's General settings. These cover the non-editorial product basics such as name, URL, description, sitemap URL, blog root URL, publishing cadence, and similar core product fields.
11
11
 
12
12
  In human-facing responses, call product `output-settings` article settings or article preferences. Use `output-settings` only when you are quoting the literal CLI command or API path.
13
13
  Use `products backlinks ...` for backlink exchange settings, credits, review queues, and reverification actions.
14
-
15
- ## Setup
16
-
14
+
15
+ ## Setup
16
+
17
17
  1. If `OUTRANK_API_KEY` is not set, ask the human for an Outrank API key from `https://outrank.so/dashboard/settings/api-keys`.
18
- 2. Store it with `outrank-cli auth login <api-key>`.
19
- 3. Verify access with `outrank-cli auth whoami`.
20
- 4. If a command fails with auth errors, tell the human exactly how to refresh the key, then retry.
21
- 5. If the environment blocks writes to the default home directory, set `OUTRANK_CONFIG_DIR` to a writable folder before using `auth login`.
18
+ 2. Store it with `outrank-cli auth login <api-key>`.
19
+ 3. Verify access with `outrank-cli auth whoami`.
20
+ 4. If a command fails with auth errors, tell the human exactly how to refresh the key, then retry.
21
+ 5. If the environment blocks writes to the default home directory, set `OUTRANK_CONFIG_DIR` to a writable folder before using `auth login`.
22
22
  6. If the API is hosted on a non-default Outrank deployment, set `OUTRANK_BASE_URL=<deployment-url>`. Use `--base-url <deployment-url>` only as a per-command override when needed.
23
-
24
- ## Discovery
25
-
26
- Run `outrank-cli --help` first if you need the command tree.
27
-
28
- Run group help when needed:
29
-
30
- - `outrank-cli auth --help`
31
- - `outrank-cli products --help`
32
- - `outrank-cli keywords --help`
33
- - `outrank-cli articles --help`
34
- - `outrank-cli subscription --help`
35
- - `outrank-cli usage --help`
36
- - `outrank-cli billing --help`
37
- - `outrank-cli auth status`
38
-
39
- Prefer inspecting before mutating:
40
-
41
- - `outrank-cli products list --limit 20`
42
- - `outrank-cli products get <productId>` for General settings
43
- - `outrank-cli products output-settings get <productId>`
44
- - `outrank-cli keywords list --product <productId> --scope all`
45
- - `outrank-cli articles list --product <productId>`
46
- - `outrank-cli articles get <articleId>`
47
- - `outrank-cli articles get-content <articleId>`
48
- - `outrank-cli articles upload-image --file <path> --article <articleId>`
49
- - `outrank-cli articles upload-featured-image <articleId> --file <path>`
50
- - `outrank-cli keywords export --product <productId>`
23
+
24
+ ## Discovery
25
+
26
+ Run `outrank-cli --help` first if you need the command tree.
27
+
28
+ Run group help when needed:
29
+
30
+ - `outrank-cli auth --help`
31
+ - `outrank-cli products --help`
32
+ - `outrank-cli keywords --help`
33
+ - `outrank-cli articles --help`
34
+ - `outrank-cli subscription --help`
35
+ - `outrank-cli usage --help`
36
+ - `outrank-cli billing --help`
37
+ - `outrank-cli auth status`
38
+
39
+ Prefer inspecting before mutating:
40
+
41
+ - `outrank-cli products list --limit 20`
42
+ - `outrank-cli products get <productId>` for General settings
43
+ - `outrank-cli products output-settings get <productId>`
44
+ - `outrank-cli keywords list --product <productId> --scope all`
45
+ - `outrank-cli articles list --product <productId>`
46
+ - `outrank-cli articles get <articleId>`
47
+ - `outrank-cli articles get-content <articleId>`
48
+ - `outrank-cli articles upload-image --file <path> --article <articleId>`
49
+ - `outrank-cli articles upload-featured-image <articleId> --file <path>`
50
+ - `outrank-cli keywords export --product <productId>`
51
51
  - `outrank-cli products target-audiences list <productId>`
52
52
  - `outrank-cli products competitors list <productId>`
53
53
  - `outrank-cli products integrations providers`
@@ -79,26 +79,26 @@ Prefer inspecting before mutating:
79
79
  - `outrank-cli products backlinks subscription <productId>`
80
80
  - `outrank-cli subscription status`
81
81
  - `outrank-cli usage stats`
82
-
83
- Interpret `auth whoami` carefully:
84
-
85
- - `organization.product_count` may represent purchased product slots, not the literal number of rows returned by `products list`.
86
-
87
- ## Write pattern
88
-
89
- For complex writes, prefer JSON via file or stdin over long shell escaping.
90
-
91
- Accepted input forms:
92
-
93
- - `--json '{...}'`
94
- - `--json-file payload.json`
95
- - `--json-stdin`
96
-
97
- Write commands currently supported:
98
-
99
- - `outrank-cli products create --json-file product.json`
100
- After create, the initial ~30-day keyword plan is queued automatically. Poll with `outrank-cli keywords generation-status --product <productId>` and then inspect `outrank-cli keywords list --product <productId>`.
101
- - `outrank-cli products update <productId> --json-file patch.json` for General settings
82
+
83
+ Interpret `auth whoami` carefully:
84
+
85
+ - `organization.product_count` may represent purchased product slots, not the literal number of rows returned by `products list`.
86
+
87
+ ## Write pattern
88
+
89
+ For complex writes, prefer JSON via file or stdin over long shell escaping.
90
+
91
+ Accepted input forms:
92
+
93
+ - `--json '{...}'`
94
+ - `--json-file payload.json`
95
+ - `--json-stdin`
96
+
97
+ Write commands currently supported:
98
+
99
+ - `outrank-cli products create --json-file product.json`
100
+ After create, the initial ~30-day keyword plan is queued automatically. Poll with `outrank-cli keywords generation-status --product <productId>` and then inspect `outrank-cli keywords list --product <productId>`.
101
+ - `outrank-cli products update <productId> --json-file patch.json` for General settings
102
102
  - `outrank-cli products output-settings update <productId> --json-file output-settings.json`
103
103
  - `outrank-cli products target-audiences replace <productId> --json-file target-audiences.json`
104
104
  - `outrank-cli products competitors replace <productId> --json-file competitors.json`
@@ -138,112 +138,113 @@ Write commands currently supported:
138
138
  - `outrank-cli products backlinks reverify <productId> <backlinkId>`
139
139
  - `outrank-cli products backlinks subscribe-quote <productId> --plan premium|enterprise`
140
140
  - `outrank-cli keywords add --product <productId> --json-file keywords.json`
141
+ - `outrank-cli keywords update <keywordId> --json-file keyword-update.json`
141
142
  - `outrank-cli keywords bulk-reschedule --json-file keyword-reschedule.json`
142
143
  - `outrank-cli keywords bulk-delete --json-file keyword-delete.json`
143
- - `outrank-cli articles update <articleId> --json-file article-patch.json`
144
- - `outrank-cli articles update-content <articleId> --json-file article-content.json`
145
- - `outrank-cli articles replace <articleId> --json-file replace.json`
146
- - `outrank-cli articles bulk-replace --json-file bulk-replace.json`
147
- - `outrank-cli articles upload-image --file local-image.png --article <articleId>`
148
- - `outrank-cli articles upload-featured-image <articleId> --file hero.jpg`
149
-
150
- Billing-management helper:
151
-
152
- - `outrank-cli billing portal-url`
153
-
154
- ## New-product preflight
155
-
156
- When the human asks to create or add a new product, do not jump straight to `products create` or a billing purchase.
157
-
158
- Treat product creation as blocked until you have either:
159
-
160
- 1. Collected the key product and article-settings inputs, or
161
- 2. Explicit human approval to keep the current defaults for anything they did not specify.
162
-
163
- Ask for missing information explicitly. Do not silently rely on defaults for editorial behavior.
164
- When the account already has products, inspect at least one existing product's article settings first so you can see the current backend's actual setting keys before you ask the human to configure a new one.
165
-
166
- Use this inspection pattern before asking article-setting questions:
167
-
168
- - `outrank-cli products list --limit 20`
169
- - `outrank-cli products output-settings get <existingProductId>`
170
-
171
- Use the returned `output-settings` object as the authoritative checklist of fields currently visible through the live API for that account. Do not rely on a hardcoded short list if the live object contains more agent-visible settings. Do not infer dashboard-only or internal generation fields that are intentionally hidden from the agent API, including `outline`, `outrank_prompt`, and `not_included_words`.
172
-
173
- When the response includes `data._meta`:
174
-
175
- - if `data._human` is present, use that as the default source for any human-facing summary
176
- - use `data._meta.sections` to decide which settings to show humans and how to group them
177
- - use `data._meta.fields.<field>.label` and `.description` instead of inventing meanings from snake_case names
178
- - use `data._meta.fields.<field>.options` for enum choices and `constraints` for numeric/color limits before proposing or writing a new value
179
- - treat `data._meta.hidden_from_human_summary_fields` as bookkeeping fields that usually should not be surfaced in prose
180
- - if a field is missing from `data._meta.fields`, do not guess what it means; say the live API did not define that field's semantics clearly
181
- - never mention database table names, raw API field names, raw enum keys, or internal ids in normal human-facing explanations unless the user explicitly asks for implementation details
182
-
183
- Minimum product brief to collect before creation:
184
-
185
- - product name
186
- - canonical website URL
187
- - product description
188
- - target audiences
189
- - competitor set
190
- - language
191
- - keyword region
192
-
193
- Article settings to confirm before creation or immediately before the first write:
194
-
195
- - tone and style
196
- - whether to auto-publish
197
- - whether to include a table of contents
198
- - whether to mention similar products
199
- - whether to include CTAs
200
- - whether to include YouTube videos, if that field exists in the inspected article settings
201
- - featured-image style, article-image style, or similar image fields, if those fields exist in the inspected article settings
202
-
203
- The list above is a minimum reminder, not the full agent-visible schema. If the inspected live output-settings object includes additional visible fields, ask about those too. Do not ask the human to configure hidden internal fields that are absent from the live object.
204
-
205
- For preset-backed fields, do not ask for free-form prose unless the backend clearly accepts arbitrary text. Many settings are select-style options. Examples may include tone, image style, or featured-image style.
206
-
207
- If the live API or current repo context does not expose the full allowed option list for a preset-backed field:
208
-
209
- - do not pretend the value is free-form
210
- - ask the human for the exact option label they want as it appears in Outrank
211
- - if helpful, show the current value from an existing product as a reference point
212
- - say clearly when the CLI exposes the field's current value but not the full enum catalog
213
-
144
+ - `outrank-cli articles update <articleId> --json-file article-patch.json`
145
+ - `outrank-cli articles update-content <articleId> --json-file article-content.json`
146
+ - `outrank-cli articles replace <articleId> --json-file replace.json`
147
+ - `outrank-cli articles bulk-replace --json-file bulk-replace.json`
148
+ - `outrank-cli articles upload-image --file local-image.png --article <articleId>`
149
+ - `outrank-cli articles upload-featured-image <articleId> --file hero.jpg`
150
+
151
+ Billing-management helper:
152
+
153
+ - `outrank-cli billing portal-url`
154
+
155
+ ## New-product preflight
156
+
157
+ When the human asks to create or add a new product, do not jump straight to `products create` or a billing purchase.
158
+
159
+ Treat product creation as blocked until you have either:
160
+
161
+ 1. Collected the key product and article-settings inputs, or
162
+ 2. Explicit human approval to keep the current defaults for anything they did not specify.
163
+
164
+ Ask for missing information explicitly. Do not silently rely on defaults for editorial behavior.
165
+ When the account already has products, inspect at least one existing product's article settings first so you can see the current backend's actual setting keys before you ask the human to configure a new one.
166
+
167
+ Use this inspection pattern before asking article-setting questions:
168
+
169
+ - `outrank-cli products list --limit 20`
170
+ - `outrank-cli products output-settings get <existingProductId>`
171
+
172
+ Use the returned `output-settings` object as the authoritative checklist of fields currently visible through the live API for that account. Do not rely on a hardcoded short list if the live object contains more agent-visible settings. Do not infer dashboard-only or internal generation fields that are intentionally hidden from the agent API, including `outline`, `outrank_prompt`, and `not_included_words`.
173
+
174
+ When the response includes `data._meta`:
175
+
176
+ - if `data._human` is present, use that as the default source for any human-facing summary
177
+ - use `data._meta.sections` to decide which settings to show humans and how to group them
178
+ - use `data._meta.fields.<field>.label` and `.description` instead of inventing meanings from snake_case names
179
+ - use `data._meta.fields.<field>.options` for enum choices and `constraints` for numeric/color limits before proposing or writing a new value
180
+ - treat `data._meta.hidden_from_human_summary_fields` as bookkeeping fields that usually should not be surfaced in prose
181
+ - if a field is missing from `data._meta.fields`, do not guess what it means; say the live API did not define that field's semantics clearly
182
+ - never mention database table names, raw API field names, raw enum keys, or internal ids in normal human-facing explanations unless the user explicitly asks for implementation details
183
+
184
+ Minimum product brief to collect before creation:
185
+
186
+ - product name
187
+ - canonical website URL
188
+ - product description
189
+ - target audiences
190
+ - competitor set
191
+ - language
192
+ - keyword region
193
+
194
+ Article settings to confirm before creation or immediately before the first write:
195
+
196
+ - tone and style
197
+ - whether to auto-publish
198
+ - whether to include a table of contents
199
+ - whether to mention similar products
200
+ - whether to include CTAs
201
+ - whether to include YouTube videos, if that field exists in the inspected article settings
202
+ - featured-image style, article-image style, or similar image fields, if those fields exist in the inspected article settings
203
+
204
+ The list above is a minimum reminder, not the full agent-visible schema. If the inspected live output-settings object includes additional visible fields, ask about those too. Do not ask the human to configure hidden internal fields that are absent from the live object.
205
+
206
+ For preset-backed fields, do not ask for free-form prose unless the backend clearly accepts arbitrary text. Many settings are select-style options. Examples may include tone, image style, or featured-image style.
207
+
208
+ If the live API or current repo context does not expose the full allowed option list for a preset-backed field:
209
+
210
+ - do not pretend the value is free-form
211
+ - ask the human for the exact option label they want as it appears in Outrank
212
+ - if helpful, show the current value from an existing product as a reference point
213
+ - say clearly when the CLI exposes the field's current value but not the full enum catalog
214
+
214
215
  Business-critical settings that may matter before article generation:
215
-
216
- - blog URL or publishing destination
217
- - internal linking preferences
218
- - image style or image-generation preferences
219
- - article examples or brand-writing examples
220
- - publishing workflow preferences such as draft-first vs direct publish
221
-
222
- If the human has not provided those business-critical settings yet, say so clearly. Explain which of them are currently exposed by `outrank-cli` and which are not. Internal linking is now exposed through the `products linking ...` subtree. For settings that are not yet supported by the current CLI surface, do not invent commands. Instead, ask the human whether to:
223
-
224
- - proceed with existing/default Outrank settings for now, or
225
- - stop product creation until those settings are provided and/or configured elsewhere
226
-
227
- Before any billing or create step, present a short confirmation summary that includes:
228
-
229
- - what will be created
230
- - what competitors and audiences will be set
231
- - which article settings will be written
232
- - which fields were confirmed from the live output-settings schema versus inferred from docs/examples
233
- - which important settings are still defaulting because they were not provided or are not yet exposed in the CLI
234
- - whether a real billing charge approval is still required
235
-
236
- ## Product workflow
237
-
216
+
217
+ - blog URL or publishing destination
218
+ - internal linking preferences
219
+ - image style or image-generation preferences
220
+ - article examples or brand-writing examples
221
+ - publishing workflow preferences such as draft-first vs direct publish
222
+
223
+ If the human has not provided those business-critical settings yet, say so clearly. Explain which of them are currently exposed by `outrank-cli` and which are not. Internal linking is exposed through the `products linking ...` subtree. For settings that are not yet supported by the current CLI surface, do not invent commands. Instead, ask the human whether to:
224
+
225
+ - proceed with existing/default Outrank settings for now, or
226
+ - stop product creation until those settings are provided and/or configured elsewhere
227
+
228
+ Before any billing or create step, present a short confirmation summary that includes:
229
+
230
+ - what will be created
231
+ - what competitors and audiences will be set
232
+ - which article settings will be written
233
+ - which fields were confirmed from the live output-settings schema versus inferred from docs/examples
234
+ - which important settings are still defaulting because they were not provided or are not yet exposed in the CLI
235
+ - whether a real billing charge approval is still required
236
+
237
+ ## Product workflow
238
+
238
239
  For a new product:
239
-
240
- 1. Gather the new-product preflight inputs above. If anything important is missing, ask the human before continuing.
241
- 2. If another paid product slot is needed, quote the billing change before creating anything.
242
- 3. After the human approves the plan, create it with `products create`.
243
- 4. Read the returned `agent_guidance`.
244
- 5. Tune article behavior with `products output-settings update`.
245
- 6. Replace the target-audience set with `products target-audiences replace`.
246
- 7. Replace the competitor set with `products competitors replace`.
240
+
241
+ 1. Gather the new-product preflight inputs above. If anything important is missing, ask the human before continuing.
242
+ 2. If another paid product slot is needed, quote the billing change before creating anything.
243
+ 3. After the human approves the plan, create it with `products create`.
244
+ 4. Read the returned `agent_guidance`.
245
+ 5. Tune article behavior with `products output-settings update`.
246
+ 6. Replace the target-audience set with `products target-audiences replace`.
247
+ 7. Replace the competitor set with `products competitors replace`.
247
248
  8. Re-read the product, article settings, target audiences, and competitors to confirm the final state.
248
249
 
249
250
  When you only need a small change, use `products update` rather than recreating the product.
@@ -371,22 +372,22 @@ Important behavior:
371
372
  - the current CLI surface still does not expose create, update, or test for some providers, and only WordPress.com and Notion currently expose an OAuth connect flow; if the human asks for unsupported operations, say they are not shipped in this CLI yet instead of inventing commands
372
373
 
373
374
  ## Keyword workflow
374
-
375
- Keyword plans now have two buckets:
376
-
377
- - scheduled keywords: already on the content calendar
378
- - stored keywords: unscheduled inventory waiting to be promoted into the plan
379
-
380
- Inspect before mutating:
381
-
382
- - `outrank-cli keywords list --product <productId> --scope scheduled`
383
- - `outrank-cli keywords list --product <productId> --scope stored`
384
- - `outrank-cli keywords list --product <productId> --scope all`
385
- - `outrank-cli keywords export --product <productId>`
386
- - `outrank-cli keywords generation-status --product <productId>`
387
-
388
- Use the returned `data.scope`, `data.scheduled`, and `data.stored` structure literally. Do not invent a different keyword model.
389
-
375
+
376
+ Keyword plans have two buckets:
377
+
378
+ - scheduled keywords: already on the content calendar
379
+ - stored keywords: unscheduled inventory waiting to be promoted into the plan
380
+
381
+ Inspect before mutating:
382
+
383
+ - `outrank-cli keywords list --product <productId> --scope scheduled`
384
+ - `outrank-cli keywords list --product <productId> --scope stored`
385
+ - `outrank-cli keywords list --product <productId> --scope all`
386
+ - `outrank-cli keywords export --product <productId>`
387
+ - `outrank-cli keywords generation-status --product <productId>`
388
+
389
+ Use the returned `data.scope`, `data.scheduled`, and `data.stored` structure literally. Do not invent a different keyword model.
390
+
390
391
  When the user asks for keyword ideas:
391
392
 
392
393
  - use `outrank-cli keywords suggest --product <productId> --theme "<theme>"` for related-keyword exploration around a theme or seed term
@@ -400,96 +401,105 @@ Before `keywords generate`:
400
401
  - if the human did not specify how many keywords to generate, ask them
401
402
  - the allowed range is 5-30, but the real maximum depends on free scheduler slots
402
403
  - check `outrank-cli keywords generation-status --product <productId>` when you need the current slot capacity
403
-
404
- To add keywords:
405
-
406
- - for direct adds, use `outrank-cli keywords add --product <productId> --json-file keywords.json`
407
- - for promoting existing stored keywords, include `stored_keyword_ids` in that JSON payload
408
-
409
- Important behavior to remember:
410
-
411
- - add is idempotent where possible; existing scheduled keywords come back as existing rather than being duplicated
412
- - stored keywords are unscheduled inventory, not disabled scheduled keywords
413
- - stored keywords are read-only inventory; they can be promoted into the plan but not deleted directly
414
- - auto-scheduling respects the backend's real planner logic, including publish days and pending downgrade limits
415
- - if keyword generation status says writes are blocked, treat both scheduled and stored keywords as read-only until the blocker clears
416
- - if the main subscription is `past_due`, keyword mutations are blocked and only reads are allowed
417
- - scheduled keywords with created or pre-created articles are read-only
418
- - keywords in `generating_article` are read-only until generation finishes
419
- - past keywords are read-only except past `scheduled` or `disabled` keywords without an article, which may still be rescheduled
420
- - if the response reports skipped keywords, explain the actual skip reason to the human instead of pretending the add fully succeeded
421
-
422
- For schedule changes:
423
-
424
- - check writability first when there is any doubt: `outrank-cli keywords generation-status --product <productId>`
425
- - reschedule one: `outrank-cli keywords reschedule <keywordId> --scheduled-for YYYY-MM-DD`
426
- - reschedule many: `outrank-cli keywords bulk-reschedule --json-file keyword-reschedule.json`
427
-
428
- For article actions:
429
-
430
- - `outrank-cli articles generate <keywordId>` is only for keywords scheduled for today
431
- - `outrank-cli articles precreate <keywordId>` is only for eligible future scheduled keywords
432
- - trial users cannot pre-create articles
433
- - past-due subscriptions block article actions
434
- - future scheduled articles cannot be manually published early through `articles update`
435
-
436
- For deletion:
437
-
438
- - delete one: `outrank-cli keywords delete <keywordId>`
439
- - delete many: `outrank-cli keywords bulk-delete --json-file keyword-delete.json`
440
-
441
- When answering humans, call the scheduled set the content plan or keyword plan. Call stored keywords unscheduled inventory or stored keywords. Do not talk about internal table names.
442
-
443
- ## Pause and resume
444
-
445
- Use:
446
-
447
- - `outrank-cli products pause <productId>`
448
- - `outrank-cli products resume <productId>`
449
-
450
- These affect billing-adjacent product state. Read the returned guidance carefully and relay any human-only step.
451
-
452
- ## Article workflow
453
-
454
- Inspect before mutating:
455
-
456
- - `outrank-cli articles list --product <productId>`
457
- - `outrank-cli articles get <articleId>`
458
- - `outrank-cli articles get-content <articleId>`
459
-
460
- Important behavior to remember:
461
-
404
+
405
+ To add keywords:
406
+
407
+ - for direct adds, use `outrank-cli keywords add --product <productId> --json-file keywords.json`
408
+ - for promoting existing stored keywords, include `stored_keyword_ids` in that JSON payload
409
+
410
+ Important behavior to remember:
411
+
412
+ - add is idempotent where possible; existing scheduled keywords come back as existing rather than being duplicated
413
+ - stored keywords are unscheduled inventory, not disabled scheduled keywords
414
+ - stored keywords are read-only inventory; they can be promoted into the plan but not deleted directly
415
+ - auto-scheduling respects the backend's real planner logic, including publish days and pending downgrade limits
416
+ - if keyword generation status says writes are blocked, treat both scheduled and stored keywords as read-only until the blocker clears
417
+ - if the main subscription is `past_due`, keyword mutations are blocked and only reads are allowed
418
+ - scheduled keywords with created or pre-created articles are read-only
419
+ - keywords in `generating_article` are read-only until generation finishes
420
+ - past keywords are read-only except past `scheduled` or `disabled` keywords without an article, which may still be rescheduled
421
+ - if the response reports skipped keywords, explain the actual skip reason to the human instead of pretending the add fully succeeded
422
+
423
+ For schedule changes:
424
+
425
+ - check writability first when there is any doubt: `outrank-cli keywords generation-status --product <productId>`
426
+ - `keywords list` uses planner-first ordering for scheduled results, so page 1 prioritizes upcoming scheduled items before past ones
427
+ - confirm keyword presence with `outrank-cli keywords list --product <productId> --scope scheduled --q "<keyword>"`; if `next_offset` is not `null`, keep paging before claiming it is missing
428
+ - keyword records return top-level `article_type`, `article_subtype`, `expected_length`, and label fields; use those directly for article-type or expected-length questions instead of checking product output-settings
429
+ - update one keyword's mutable fields: `outrank-cli keywords update <keywordId> --json '{"instructions":"..."}'`
430
+ - answer or replace the keyword's quality questions with `outrank-cli keywords update <keywordId> --json '{"quality_questions":[{"id":"...","question":"...","answer":"..."}]}'`
431
+ - `outrank-cli keywords get <keywordId>` returns `article_type_options`; use those values when patching `article_type`, `article_subtype`, or `expected_length`
432
+ - `outrank-cli keywords update <keywordId> --json '{"article_type":"guide","article_subtype":"explainer","expected_length":"long"}'` mirrors the scheduler card Article Type Settings modal and rejects values outside the allowed option lists
433
+ - reschedule one: `outrank-cli keywords update <keywordId> --json '{"scheduled_for":"YYYY-MM-DD"}'`
434
+ - reschedule many: `outrank-cli keywords bulk-reschedule --json-file keyword-reschedule.json`
435
+
436
+ For article actions:
437
+
438
+ - `outrank-cli articles generate <keywordId>` is only for keywords scheduled for today
439
+ - `outrank-cli articles precreate <keywordId>` is only for eligible future scheduled keywords
440
+ - article records with a linked scheduled keyword also return top-level `article_type`, `article_subtype`, `expected_length`, and label fields
441
+ - trial users cannot pre-create articles
442
+ - past-due subscriptions block article actions
443
+ - future scheduled articles cannot be manually published early through `articles update`
444
+
445
+ For deletion:
446
+
447
+ - delete one: `outrank-cli keywords delete <keywordId>`
448
+ - delete many: `outrank-cli keywords bulk-delete --json-file keyword-delete.json`
449
+
450
+ When answering humans, call the scheduled set the content plan or keyword plan. Call stored keywords unscheduled inventory or stored keywords. Do not talk about internal table names.
451
+
452
+ ## Pause and resume
453
+
454
+ Use:
455
+
456
+ - `outrank-cli products pause <productId>`
457
+ - `outrank-cli products resume <productId>`
458
+
459
+ These affect billing-adjacent product state. Read the returned guidance carefully and relay any human-only step.
460
+
461
+ ## Article workflow
462
+
463
+ Inspect before mutating:
464
+
465
+ - `outrank-cli articles list --product <productId>`
466
+ - `outrank-cli articles get <articleId>`
467
+ - `outrank-cli articles get-content <articleId>`
468
+
469
+ Important behavior to remember:
470
+
462
471
  - article metadata and history mirror the current app behavior, including soft-delete instead of hard-delete
463
472
  - article bodies are markdown in the backend; `--format html` is rendered output, not the source of truth
464
473
  - featured image is separate from the markdown body and can be updated either through the normal article update payload via `image_url` or by local-file upload with `articles upload-featured-image`
465
474
  - in-content images can be uploaded from local files with `articles upload-image`; the command returns a hosted URL and alt text for markdown insertion or replacement
466
475
  - per-article instructions live on the linked scheduled keyword, so they are only editable while that planner relationship still exists and is writable
476
+ - `articles get <articleId>` returns `article_type_options`; use those values when patching `article_type`, `article_subtype`, or `expected_length`
477
+ - `articles update --json '{"article_type":"guide","article_subtype":"howTo","expected_length":"medium"}'` mirrors the dashboard Article Type Settings modal and rejects values outside the allowed option lists
467
478
  - `articles update --json '{"status":"published"}'` attempts a real publish through the product's active integration for eligible attached articles; if the remote publish fails, inspect the returned error and the article's `publish_error`
468
479
  - slug is readable for reference but read-only in the agent API
469
480
  - `articles generate <keywordId>` mirrors the current create-and-publish flow for a scheduled keyword
470
481
  - `articles precreate <keywordId>` mirrors the current pre-generation flow; after calling it, inspect the keyword state until it moves from `generating_article` to `pregenerated` or back to `scheduled`
471
- - `articles retry-publish <articleId>` only works for generated articles with a publish error
472
- - `articles bulk-replace` is preview-first; review the returned excerpts, then rerun with `"confirm": true` in the JSON payload to write changes
473
-
474
- ## Buying more product slots
475
-
476
- Always do this in two steps:
477
-
478
- 1. Quote the change: `outrank-cli billing purchase-products quote --additional-products <n>`
479
- 2. If the human approves, submit the purchase with the exact quoted recurring total:
480
- `outrank-cli billing purchase-products buy --additional-products <n> --confirm-charge-cents <quoted> --idempotency-key <stable-random-key>`
481
-
482
- Never guess `confirm-charge-cents`. Use the server-quoted number.
483
- Do not ask for billing approval until you have already clarified the intended product configuration and any defaulted article/publishing settings.
484
-
485
- ## Error handling
486
-
487
- - If `ok` is `false`, read both `error.message` and `agent_guidance`.
488
- - For `401`, help the human refresh `OUTRANK_API_KEY`.
489
- - For `403` or `409`, the guidance usually tells you whether to inspect state, pause another product, or ask the human to approve a billing step.
490
- - For `402`, stop retrying and ask the human to fix billing.
491
-
482
+ - `articles retry-publish <articleId>` only works for generated articles with a publish error
483
+ - `articles bulk-replace` is preview-first; review the returned excerpts, then rerun with `"confirm": true` in the JSON payload to write changes
484
+
485
+ ## Buying more product slots
486
+
487
+ Always do this in two steps:
488
+
489
+ 1. Quote the change: `outrank-cli billing purchase-products quote --additional-products <n>`
490
+ 2. If the human approves, submit the purchase with the exact quoted recurring total:
491
+ `outrank-cli billing purchase-products buy --additional-products <n> --confirm-charge-cents <quoted> --idempotency-key <stable-random-key>`
492
+
493
+ Never guess `confirm-charge-cents`. Use the server-quoted number.
494
+ Do not ask for billing approval until you have already clarified the intended product configuration and any defaulted article/publishing settings.
495
+
496
+ ## Error handling
497
+
498
+ - If `ok` is `false`, read both `error.message` and `agent_guidance`.
499
+ - For `401`, help the human refresh `OUTRANK_API_KEY`.
500
+ - For `403` or `409`, the guidance usually tells you whether to inspect state, pause another product, or ask the human to approve a billing step.
501
+ - For `402`, stop retrying and ask the human to fix billing.
502
+
492
503
  ## Current limitation
493
504
 
494
- The implementation plan is broader than the current live API. Keywords, core article flows, linking, backlink exchange management, and the current integration-management flows are now exposed in `outrank-cli`, including direct setup for webhook, Ghost, Shopify, Webflow, Wix, Framer, WordPress Plugin, and Next.js Blog, plus OAuth flows for WordPress.com and Notion. Purchasing or changing backlink add-ons and some onboarding flows still require the dashboard. If the user asks for something not present in `outrank-cli --help`, say that exact command surface is not shipped yet and do not invent unsupported commands.
495
-
505
+ The implementation plan is broader than the current live API. Keywords, core article flows, linking, backlink exchange management, and the current integration-management flows are exposed in `outrank-cli`, including direct setup for webhook, Ghost, Shopify, Webflow, Wix, Framer, WordPress Plugin, and Next.js Blog, plus OAuth flows for WordPress.com and Notion. Purchasing or changing backlink add-ons and some onboarding flows still require the dashboard. If the user asks for something not present in `outrank-cli --help`, say that exact command surface is not shipped yet and do not invent unsupported commands.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "outrank-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Agent-first CLI for the Outrank agent API",
5
5
  "type": "module",
6
6
  "files": [
@@ -16,10 +16,10 @@ export const KEYWORDS_HELP = `Usage:
16
16
  outrank-cli keywords export --product <product-id>
17
17
  outrank-cli keywords generation-status --product <product-id>
18
18
  outrank-cli keywords add --product <product-id> --json <object>
19
+ outrank-cli keywords update <keyword-id> --json <object>
19
20
  outrank-cli keywords suggest --product <product-id> (--keyword <text> | --theme <text>) [--keyword-region <code>] [--limit <n>]
20
21
  outrank-cli keywords generate --product <product-id> --count <n> [--source competitors|audiences|both] [--competitor <competitor-id> ...] [--audience <text> ...]
21
22
  outrank-cli keywords bulk-process --product <product-id> --json <object> [--keyword-region <code>]
22
- outrank-cli keywords reschedule <keyword-id> --scheduled-for <date>
23
23
  outrank-cli keywords bulk-reschedule --json <object>
24
24
  outrank-cli keywords delete <keyword-id>
25
25
  outrank-cli keywords bulk-delete --json <object>
@@ -29,14 +29,16 @@ JSON Input:
29
29
 
30
30
  Examples:
31
31
  outrank-cli keywords list --product 00000000-0000-0000-0000-000000000000 --scope all
32
+ outrank-cli keywords list --product 00000000-0000-0000-0000-000000000000 --scope scheduled --q "best seo tools"
32
33
  outrank-cli keywords export --product 00000000-0000-0000-0000-000000000000
33
34
  outrank-cli keywords generation-status --product 00000000-0000-0000-0000-000000000000
34
35
  outrank-cli keywords add --product 00000000-0000-0000-0000-000000000000 --json-file keywords.json
36
+ outrank-cli keywords update 00000000-0000-0000-0000-000000000000 --json '{"instructions":"Write for beginners and include a step-by-step setup section"}'
37
+ outrank-cli keywords update 00000000-0000-0000-0000-000000000000 --json '{"scheduled_for":"2026-05-20"}'
35
38
  outrank-cli keywords suggest --product 00000000-0000-0000-0000-000000000000 --theme "email marketing" --limit 8
36
39
  outrank-cli keywords generate --product 00000000-0000-0000-0000-000000000000 --count 10 --source both
37
40
  outrank-cli keywords generate --product 00000000-0000-0000-0000-000000000000 --count 5 --source competitors --competitor 11111111-1111-1111-1111-111111111111
38
41
  outrank-cli keywords bulk-process --product 00000000-0000-0000-0000-000000000000 --json '{"keywords":["keyword one","keyword two"]}'
39
- outrank-cli keywords reschedule 00000000-0000-0000-0000-000000000000 --scheduled-for 2026-05-20
40
42
  outrank-cli keywords bulk-reschedule --json-file keyword-reschedule.json
41
43
  outrank-cli keywords delete 00000000-0000-0000-0000-000000000000
42
44
  `;
@@ -131,6 +133,17 @@ const handleKeywordsAdd = async (parsed) => {
131
133
  return response.payload;
132
134
  };
133
135
 
136
+ const handleKeywordsUpdate = async (parsed) => {
137
+ const keywordId = getRequiredPositional(parsed, 0, '<keyword-id>');
138
+ const body = await readJsonInput(parsed);
139
+ const response = await requestAgentApi(parsed, {
140
+ method: 'PATCH',
141
+ path: `/keywords/${keywordId}`,
142
+ body,
143
+ });
144
+ return response.payload;
145
+ };
146
+
134
147
  const handleKeywordsSuggest = async (parsed) => {
135
148
  const keyword = getOption(parsed, 'keyword');
136
149
  const theme = getOption(parsed, 'theme');
@@ -228,26 +241,6 @@ const handleKeywordsBulkProcess = async (parsed) => {
228
241
  return response.payload;
229
242
  };
230
243
 
231
- const handleKeywordsReschedule = async (parsed) => {
232
- const keywordId = getRequiredPositional(parsed, 0, '<keyword-id>');
233
- const scheduledFor = getOption(parsed, 'scheduled-for');
234
- if (!scheduledFor) {
235
- throw Object.assign(new Error('Missing required option: --scheduled-for <date>.'), {
236
- cliCode: 'CLI_INVALID_USAGE',
237
- guidance: 'Pass the target schedule date with `--scheduled-for YYYY-MM-DD` or an ISO timestamp.',
238
- });
239
- }
240
-
241
- const response = await requestAgentApi(parsed, {
242
- method: 'PATCH',
243
- path: `/keywords/${keywordId}`,
244
- body: {
245
- scheduled_for: scheduledFor,
246
- },
247
- });
248
- return response.payload;
249
- };
250
-
251
244
  const handleKeywordsBulkReschedule = async (parsed) => {
252
245
  const body = await readJsonInput(parsed);
253
246
  const response = await requestAgentApi(parsed, {
@@ -287,7 +280,7 @@ export const handleKeywordsCommand = async (argv) => {
287
280
  {
288
281
  usage: KEYWORDS_HELP.trim(),
289
282
  },
290
- 'Choose one of: list, get, export, generation-status, add, suggest, generate, bulk-process, reschedule, bulk-reschedule, delete, bulk-delete.',
283
+ 'Choose one of: list, get, export, generation-status, add, update, suggest, generate, bulk-process, bulk-reschedule, delete, bulk-delete.',
291
284
  );
292
285
  }
293
286
 
@@ -296,10 +289,10 @@ export const handleKeywordsCommand = async (argv) => {
296
289
  if (subcommand === 'export') return handleKeywordsExport(parsed);
297
290
  if (subcommand === 'generation-status') return handleKeywordsGenerationStatus(parsed);
298
291
  if (subcommand === 'add') return handleKeywordsAdd(parsed);
292
+ if (subcommand === 'update') return handleKeywordsUpdate(parsed);
299
293
  if (subcommand === 'suggest') return handleKeywordsSuggest(parsed);
300
294
  if (subcommand === 'generate') return handleKeywordsGenerate(parsed);
301
295
  if (subcommand === 'bulk-process') return handleKeywordsBulkProcess(parsed);
302
- if (subcommand === 'reschedule') return handleKeywordsReschedule(parsed);
303
296
  if (subcommand === 'bulk-reschedule') return handleKeywordsBulkReschedule(parsed);
304
297
  if (subcommand === 'delete') return handleKeywordsDelete(parsed);
305
298
  if (subcommand === 'bulk-delete') return handleKeywordsBulkDelete(parsed);