neatlogs-cli 0.1.0-team-test.1
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/CHANGELOG.md +11 -0
- package/README.md +602 -0
- package/SECURITY.md +68 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +183470 -0
- package/docs/command-reference.md +290 -0
- package/package.json +58 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
# NeatLogs CLI
|
|
2
|
+
|
|
3
|
+
Use the CLI to inspect and manage your NeatLogs projects from a terminal or an automation agent.
|
|
4
|
+
|
|
5
|
+
## Choose the right credential
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
flowchart LR
|
|
9
|
+
Start{"Who is using the CLI?"}
|
|
10
|
+
Human["Human"]
|
|
11
|
+
Agent["AI agent or CI"]
|
|
12
|
+
App["Application sending traces"]
|
|
13
|
+
OAuth["Browser login or Device Flow"]
|
|
14
|
+
ServiceToken["Service-account token"]
|
|
15
|
+
IngestKey["Ingest credential"]
|
|
16
|
+
Vault["Stored in the OS credential vault"]
|
|
17
|
+
SecretStore["Provided by an agent or CI secret store"]
|
|
18
|
+
AppSecret["Provided to the SDK as an application secret"]
|
|
19
|
+
|
|
20
|
+
Start --> Human --> OAuth --> Vault
|
|
21
|
+
Start --> Agent --> ServiceToken --> SecretStore
|
|
22
|
+
Start --> App --> IngestKey --> AppSecret
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- Humans use browser OAuth or Device Flow.
|
|
26
|
+
- Codex, Claude Code, CI, and other unattended clients use a service-account token.
|
|
27
|
+
- SDKs and applications use an ingest credential to send traces.
|
|
28
|
+
|
|
29
|
+
## Human quickstart
|
|
30
|
+
|
|
31
|
+
1. Install the CLI and confirm that it runs.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install --global neatlogs-cli@team-test
|
|
35
|
+
neatlogs --help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
2. Save the host and sign in through your browser.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
neatlogs profile set work --host '<https-app-origin>'
|
|
42
|
+
neatlogs --profile work auth login
|
|
43
|
+
# Remote/headless alternative:
|
|
44
|
+
neatlogs --profile work auth login --device
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
3. List the projects you can access.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
neatlogs --profile work projects list
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
4. Save the project you want this profile to use.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
neatlogs profile set work --host '<https-app-origin>' --project '<project-uuid>'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
5. Check your identity and read recent traces.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
neatlogs --profile work whoami
|
|
63
|
+
neatlogs --profile work traces list --limit 10
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`profile set` stores non-secret host and project preferences. Login stores the
|
|
67
|
+
OAuth credentials separately in the native operating-system vault.
|
|
68
|
+
|
|
69
|
+
## Request only the permissions you need
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Default read-oriented login
|
|
73
|
+
neatlogs --profile work auth login
|
|
74
|
+
|
|
75
|
+
# Add only the write permissions required for evaluation work
|
|
76
|
+
neatlogs --profile work auth login \
|
|
77
|
+
--scope context:read observability:read evaluation:read evaluation:write offline_access
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The consent page lists only the permissions requested by this login command.
|
|
81
|
+
`offline_access` allows refresh tokens; it is not an API permission shown by
|
|
82
|
+
`whoami`.
|
|
83
|
+
|
|
84
|
+
## Agent and CI automation
|
|
85
|
+
|
|
86
|
+
In **Settings → Service Accounts**, create a dedicated account, bind only the
|
|
87
|
+
required projects and role, and choose the minimum scopes. Inject
|
|
88
|
+
`NEATLOGS_TOKEN` through the agent or CI secret store; environment tokens are
|
|
89
|
+
never written to the OAuth keychain.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
export NEATLOGS_TOKEN='<service-account-token>'
|
|
93
|
+
export NEATLOGS_PROJECT_ID='<project-uuid>'
|
|
94
|
+
export NEATLOGS_HOST='<https-api-origin>'
|
|
95
|
+
|
|
96
|
+
neatlogs projects current --json
|
|
97
|
+
neatlogs whoami --json
|
|
98
|
+
neatlogs traces list --limit 10 --json
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Revoking the access token immediately stops later requests without disabling
|
|
102
|
+
the service account. `NEATLOGS_API_KEY` remains a legacy fallback; if it and
|
|
103
|
+
`NEATLOGS_TOKEN` are both set, they must contain the same value.
|
|
104
|
+
|
|
105
|
+
## Credential storage and security
|
|
106
|
+
|
|
107
|
+
Human login uses Authorization Code with PKCE and an exact `127.0.0.1`
|
|
108
|
+
callback. `--device` explicitly selects Device Flow for a remote or headless
|
|
109
|
+
terminal. OAuth access and refresh tokens are bound to the exact host, issuer,
|
|
110
|
+
and profile, then stored in macOS Keychain, Windows Credential Manager, or
|
|
111
|
+
Linux Secret Service.
|
|
112
|
+
|
|
113
|
+
The CLI does not consult Git credential configuration and never silently falls
|
|
114
|
+
back to a file. Linux requires libsecret and a running Secret Service
|
|
115
|
+
implementation; the CLI does not fall back to the kernel keyring or a file when
|
|
116
|
+
that service is unavailable. On POSIX, protected plaintext storage is available
|
|
117
|
+
only with `--allow-file-credentials`; it uses directory mode `0700`, file mode
|
|
118
|
+
`0600`, and warns whenever it is used. Windows rejects that option because
|
|
119
|
+
equivalent ACL enforcement is not implemented.
|
|
120
|
+
|
|
121
|
+
Credentials are never accepted as command-line flags. The CLI never follows
|
|
122
|
+
redirects, executes arbitrary API URLs, or fetches a live API schema. Recognized
|
|
123
|
+
`nloa_`, `nlsa_`, and `nlpk_` prefixes select exactly one credential class; a
|
|
124
|
+
foreign or mismatched prefix is rejected without fallback.
|
|
125
|
+
|
|
126
|
+
`schema` inspects the release-embedded contract, not active deployment flags.
|
|
127
|
+
Each operation carries `x-neatlogs-operation-gate`; only `always` is enabled by
|
|
128
|
+
default, while every other gate must be enabled by the server before the
|
|
129
|
+
operation is callable.
|
|
130
|
+
|
|
131
|
+
## Commands
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
neatlogs --profile <name> auth login [--device] [--allow-file-credentials] [--scope <scope...>]
|
|
135
|
+
neatlogs --profile <name> auth status
|
|
136
|
+
neatlogs --profile <name> auth logout [--all] [--local-only]
|
|
137
|
+
neatlogs profile list
|
|
138
|
+
neatlogs profile show [name]
|
|
139
|
+
neatlogs profile set <name> --host <https-origin> [--organization <uuid>] [--project <uuid>]
|
|
140
|
+
neatlogs profile use <name>
|
|
141
|
+
# Authenticated profiles must be logged out before deletion.
|
|
142
|
+
neatlogs profile delete <name>
|
|
143
|
+
neatlogs projects current
|
|
144
|
+
neatlogs projects create --organization <uuid> --name <name> [--timezone <iana>] [--idempotency-key <uuid>]
|
|
145
|
+
neatlogs projects update [--name <name>] [--timezone <iana-or-null>] [--idempotency-key <uuid>]
|
|
146
|
+
neatlogs account profile show
|
|
147
|
+
neatlogs notifications preferences show
|
|
148
|
+
neatlogs orgs list [--limit 1-100] [--cursor <opaque-cursor>]
|
|
149
|
+
neatlogs orgs get <organization-uuid>
|
|
150
|
+
neatlogs orgs members list <organization-uuid> [--limit 1-100] [--cursor <opaque-cursor>]
|
|
151
|
+
neatlogs orgs members get <organization-uuid> <user-uuid>
|
|
152
|
+
neatlogs orgs members update-role <organization-uuid> <user-uuid> --membership-id <membership-uuid> --expected-role owner|admin|member|guest --role admin|member|guest [--idempotency-key <uuid>]
|
|
153
|
+
neatlogs orgs members remove <organization-uuid> <user-uuid> --membership-id <membership-uuid> --expected-role owner|admin|member|guest --confirm <membership-uuid> [--idempotency-key <uuid>]
|
|
154
|
+
neatlogs orgs invitations list <organization-uuid> [--state all|pending|expired] [--limit 1-100] [--cursor <opaque-cursor>]
|
|
155
|
+
neatlogs orgs invitations invite <organization-uuid> --email <email> --role admin|member|guest [--idempotency-key <uuid>]
|
|
156
|
+
neatlogs orgs invitations resend <organization-uuid> <invitation-uuid> --email <email> [--idempotency-key <uuid>]
|
|
157
|
+
neatlogs orgs invitations revoke <organization-uuid> <invitation-uuid> --email <email> --confirm <invitation-uuid> [--idempotency-key <uuid>]
|
|
158
|
+
printf '%s' "$INVITATION_TOKEN" | neatlogs orgs invitations accept --token-stdin [--idempotency-key <uuid>]
|
|
159
|
+
neatlogs orgs roles list <organization-uuid> --action invitation|member-role-change
|
|
160
|
+
neatlogs orgs audit list <organization-uuid> [--limit 1-100] [--cursor <opaque-cursor>]
|
|
161
|
+
neatlogs service-accounts create <organization-uuid> --name <name> --binding <project-uuid=project_admin|project_member|project_viewer> [--binding ...] [--description <text>] [--idempotency-key <uuid>]
|
|
162
|
+
neatlogs service-accounts bindings add <service-account-uuid> --project-id <project-uuid> --role project_admin|project_member|project_viewer [--idempotency-key <uuid>]
|
|
163
|
+
neatlogs service-accounts bindings set-role <service-account-uuid> <binding-uuid> --role project_admin|project_member|project_viewer [--idempotency-key <uuid>]
|
|
164
|
+
neatlogs service-accounts bindings remove <service-account-uuid> <binding-uuid> --confirm <binding-uuid> [--idempotency-key <uuid>]
|
|
165
|
+
neatlogs billing subscription <organization-uuid>
|
|
166
|
+
neatlogs billing plans <organization-uuid>
|
|
167
|
+
neatlogs usage show <organization-uuid>
|
|
168
|
+
neatlogs usage alerts <organization-uuid> [--state all|unread|unacknowledged|unread-and-unacknowledged] [--limit 1-100] [--cursor <opaque-cursor>]
|
|
169
|
+
neatlogs projects list [--organization <uuid>] [--include-archived] [--limit 1-100] [--cursor <opaque-cursor>]
|
|
170
|
+
neatlogs skills list [--include-archived] [--limit 1-100] [--cursor <opaque-cursor>]
|
|
171
|
+
neatlogs skills get <skill-uuid>
|
|
172
|
+
neatlogs skills import --content-stdin [--name <lowercase-kebab>] [--description <text>] [--idempotency-key <uuid>]
|
|
173
|
+
neatlogs skills update <skill-uuid> --body-stdin [--idempotency-key <uuid>]
|
|
174
|
+
neatlogs skills delete <skill-uuid> --confirm <skill-uuid> [--idempotency-key <uuid>]
|
|
175
|
+
neatlogs whoami
|
|
176
|
+
neatlogs alerts list [--enabled all|true|false] [--rule-type threshold|per_event|compound|ingestion_health|metric_threshold] [--limit 1-100] [--cursor <opaque-cursor>]
|
|
177
|
+
neatlogs alerts get <alert-rule-uuid>
|
|
178
|
+
printf '%s' "$ALERT_JSON" | neatlogs alerts create --body-stdin [--idempotency-key <uuid>]
|
|
179
|
+
printf '%s' "$ALERT_PATCH_JSON" | neatlogs alerts update <alert-rule-uuid> --body-stdin [--idempotency-key <uuid>]
|
|
180
|
+
neatlogs alerts enable|disable <alert-rule-uuid> [--idempotency-key <uuid>]
|
|
181
|
+
neatlogs alerts delete <alert-rule-uuid> --confirm <alert-rule-uuid> [--idempotency-key <uuid>]
|
|
182
|
+
neatlogs alerts history [--alert-rule-id <uuid>] [--start-time <utc>] [--end-time <utc>] [--limit 1-100] [--cursor <opaque-cursor>]
|
|
183
|
+
neatlogs alerts changes <alert-rule-uuid> [--limit 1-100] [--cursor <opaque-cursor>]
|
|
184
|
+
neatlogs detections list [--status active|inactive|all] [--group <uuid>] [--limit 1-100] [--cursor <opaque-cursor>]
|
|
185
|
+
neatlogs detections get <detection-uuid>
|
|
186
|
+
neatlogs detections hits <detection-uuid> [--limit 1-100] [--cursor <opaque-cursor>]
|
|
187
|
+
neatlogs detections history <detection-uuid> [--limit 1-100] [--cursor <opaque-cursor>]
|
|
188
|
+
neatlogs detections trends <detection-uuid> --from <utc> --to <utc> [--granularity hour|day|week]
|
|
189
|
+
neatlogs prompts list [--name <exact-name>] [--source <source>] [--label <label>] [--limit 1-100] [--cursor <opaque-cursor>]
|
|
190
|
+
neatlogs prompts get <prompt-version-uuid>
|
|
191
|
+
neatlogs prompts history <prompt-version-uuid> [--limit 1-100] [--cursor <opaque-cursor>]
|
|
192
|
+
neatlogs prompts diff <from-version-uuid> <to-version-uuid>
|
|
193
|
+
neatlogs prompts create (--body-stdin | --name <name> (--content <text> | --content-stdin | --messages <json>)) [--config <json>] [--variables <json>] [--display-name <name>] [--role <role>] [--tags <csv>] [--commit-message <message>] [--idempotency-key <uuid>]
|
|
194
|
+
neatlogs prompts label <prompt-version-uuid> <label> [--idempotency-key <uuid>]
|
|
195
|
+
neatlogs prompts tag-add <prompt-version-uuid> <tag> [--idempotency-key <uuid>]
|
|
196
|
+
neatlogs prompts tag-remove <prompt-version-uuid> <tag> [--idempotency-key <uuid>]
|
|
197
|
+
neatlogs prompts delete <prompt-version-uuid> --confirm <prompt-version-uuid> [--idempotency-key <uuid>]
|
|
198
|
+
neatlogs evals list [--status draft|active|completed|archived|all] [--limit 1-100] [--cursor <opaque-cursor>]
|
|
199
|
+
neatlogs evals create --body-stdin [--idempotency-key <uuid>]
|
|
200
|
+
neatlogs evals launch <evaluation-uuid> --assign-me [--review-duration <duration>] [--idempotency-key <uuid>]
|
|
201
|
+
neatlogs evals close <evaluation-uuid> --confirm <evaluation-uuid> [--idempotency-key <uuid>]
|
|
202
|
+
neatlogs evals get <evaluation-uuid>
|
|
203
|
+
neatlogs evals form get <evaluation-uuid>
|
|
204
|
+
neatlogs evals form set <evaluation-uuid> --body-stdin [--idempotency-key <uuid>]
|
|
205
|
+
neatlogs evals update <evaluation-uuid> --body-stdin [--idempotency-key <uuid>]
|
|
206
|
+
neatlogs evals progress <evaluation-uuid>
|
|
207
|
+
neatlogs evals items list <evaluation-uuid> [--limit 1-100] [--cursor <opaque-cursor>]
|
|
208
|
+
neatlogs evals items get <evaluation-uuid> <item-uuid>
|
|
209
|
+
neatlogs evals assignments list <evaluation-uuid> <item-uuid>
|
|
210
|
+
neatlogs evals review get <evaluation-uuid> <item-uuid> [--assignment-id <uuid>]
|
|
211
|
+
neatlogs evals review draft <evaluation-uuid> <item-uuid> --body-stdin [--assignment-id <uuid>] [--idempotency-key <key>]
|
|
212
|
+
neatlogs evals review submit <evaluation-uuid> <item-uuid> --body-stdin [--assignment-id <uuid>] [--idempotency-key <key>]
|
|
213
|
+
neatlogs evals schedules list [--status draft|active|completed|archived|all] [--limit 1-100] [--cursor <opaque-cursor>]
|
|
214
|
+
neatlogs evals schedules get <schedule-uuid>
|
|
215
|
+
neatlogs evals schedules update <schedule-uuid> --batch-schedule <duration> [--idempotency-key <uuid>]
|
|
216
|
+
neatlogs analytics views save --body-stdin [--idempotency-key <uuid>]
|
|
217
|
+
neatlogs feedback create --trace <trace-id> --body-stdin [--idempotency-key <uuid>]
|
|
218
|
+
neatlogs feedback update <feedback-uuid> --trace <trace-id> --body-stdin [--idempotency-key <uuid>]
|
|
219
|
+
neatlogs feedback delete <feedback-uuid> --trace <trace-id> --confirm <feedback-uuid> [--idempotency-key <uuid>]
|
|
220
|
+
neatlogs feedback span-set <span-id> --trace <trace-id> --body-stdin [--idempotency-key <uuid>]
|
|
221
|
+
neatlogs feedback span-delete <span-id> --trace <trace-id> --confirm <span-id> [--idempotency-key <uuid>]
|
|
222
|
+
neatlogs comments create --trace <trace-id> --thread <thread-uuid> --content-stdin [--idempotency-key <uuid>]
|
|
223
|
+
neatlogs comments update <message-uuid> --trace <trace-id> --thread <thread-uuid> --content-stdin [--idempotency-key <uuid>]
|
|
224
|
+
neatlogs comments delete <message-uuid> --trace <trace-id> --thread <thread-uuid> --confirm <message-uuid> [--idempotency-key <uuid>]
|
|
225
|
+
neatlogs integrations providers
|
|
226
|
+
neatlogs integrations list
|
|
227
|
+
neatlogs webhooks create --body-stdin [--idempotency-key <uuid>]
|
|
228
|
+
neatlogs webhooks update <webhook-uuid> --body-stdin [--idempotency-key <uuid>]
|
|
229
|
+
neatlogs webhooks enable <webhook-uuid> [--idempotency-key <uuid>]
|
|
230
|
+
neatlogs webhooks disable <webhook-uuid> [--idempotency-key <uuid>]
|
|
231
|
+
neatlogs webhooks delete <webhook-uuid> --confirm <webhook-uuid> [--idempotency-key <uuid>]
|
|
232
|
+
neatlogs filters list [--limit 1-100] [--cursor <opaque-cursor>]
|
|
233
|
+
neatlogs filters get <saved-filter-uuid>
|
|
234
|
+
neatlogs traces list [--from <rfc3339>] [--to <rfc3339>] [--limit 1-50] [--cursor <opaque-cursor>]
|
|
235
|
+
neatlogs traces get <trace-id>
|
|
236
|
+
neatlogs traces export <trace-id> [--format json|markdown|csv]
|
|
237
|
+
neatlogs traces update-metadata <trace-id> --body-stdin [--idempotency-key <uuid>]
|
|
238
|
+
neatlogs traces search <query> [--from <rfc3339>] [--to <rfc3339>] [--workflow <name>] [--session <id>] [--limit 1-50] [--cursor <opaque-cursor>]
|
|
239
|
+
neatlogs traces semantic-search <query> [--from <rfc3339>] [--to <rfc3339>] [--workflow <name>] [--session <id>] [--limit 1-50] [--cursor <opaque-cursor>]
|
|
240
|
+
neatlogs traces spans list <trace-id> [--status <status>] [--type <type>] [--limit 1-50] [--cursor <opaque-cursor>]
|
|
241
|
+
neatlogs traces spans get <trace-id> <span-id>
|
|
242
|
+
neatlogs traces raw-spans <trace-id> [--status <status>] [--type <type>] [--limit 1-50] [--cursor <opaque-cursor>]
|
|
243
|
+
neatlogs traces payload <trace-id> <span-id> --fields input[,output,error]
|
|
244
|
+
neatlogs sessions list [--from <rfc3339>] [--to <rfc3339>] [--limit 1-50] [--cursor <opaque-cursor>]
|
|
245
|
+
neatlogs sessions get <session-id> [--limit 1-50] [--cursor <opaque-cursor>]
|
|
246
|
+
neatlogs sessions export <session-id> [--format json|markdown|csv]
|
|
247
|
+
neatlogs guest-links list [--limit 1-50] [--cursor <opaque-cursor>]
|
|
248
|
+
neatlogs guest-links get <guest-link-uuid>
|
|
249
|
+
neatlogs guest-links mint --evaluation <evaluation-uuid> --recipient-email <email> [--idempotency-key <uuid>]
|
|
250
|
+
neatlogs guest-links rotate <guest-link-uuid> [--idempotency-key <uuid>]
|
|
251
|
+
neatlogs guest-links revoke <guest-link-uuid> --confirm <guest-link-uuid> [--idempotency-key <uuid>]
|
|
252
|
+
neatlogs guest context --request-stdin [--cursor <cursor>] [--limit 1-25]
|
|
253
|
+
neatlogs guest submit <item-id> --request-stdin [--idempotency-key <uuid>]
|
|
254
|
+
neatlogs sharing traces get <trace-id>
|
|
255
|
+
neatlogs api-keys list [--limit 1-50] [--cursor <opaque-cursor>]
|
|
256
|
+
neatlogs ingest-credentials list [--limit 1-50] [--cursor <opaque-cursor>]
|
|
257
|
+
neatlogs api-keys create --name <name> --scope <scope> [--scope <scope>] [--expires-in-days 1-365] [--rate-limit 1-600]
|
|
258
|
+
neatlogs api-keys rotate <credential-uuid> --confirm <credential-uuid>
|
|
259
|
+
neatlogs api-keys revoke <credential-uuid> --confirm <credential-uuid>
|
|
260
|
+
neatlogs ingest-credentials create --name <name> [--expires-in-days 1-365]
|
|
261
|
+
neatlogs ingest-credentials rotate <credential-uuid> --confirm <credential-uuid>
|
|
262
|
+
neatlogs ingest-credentials revoke <credential-uuid> --confirm <credential-uuid>
|
|
263
|
+
neatlogs mcp status
|
|
264
|
+
neatlogs coding-tools status
|
|
265
|
+
neatlogs --project <uuid> api <operationId> [--param <name=value...>] [--query <name=value...>]
|
|
266
|
+
printf '%s' '{"q":"failed checkout"}' | neatlogs --project <uuid> api post_api_v1_public_search_traces --body-stdin
|
|
267
|
+
neatlogs schema list
|
|
268
|
+
neatlogs schema search <query>
|
|
269
|
+
neatlogs schema show <operationId>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
For confidential or multiline prompt text, prefer bounded stdin so content is
|
|
273
|
+
not exposed in shell history or process arguments. Prompt content is limited to
|
|
274
|
+
60 KiB within the Public API's 64 KiB JSON request ceiling:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
neatlogs prompts create --name support-answer --content-stdin < prompt.txt
|
|
278
|
+
neatlogs prompts create --body-stdin < complete-prompt-request.json
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Use `--body-stdin` when messages, variables, configuration, or commit metadata
|
|
282
|
+
are also sensitive. It is mutually exclusive with individual prompt field
|
|
283
|
+
options and validates the complete request before sending it.
|
|
284
|
+
|
|
285
|
+
Version creation and label activation are intentionally separate authorization
|
|
286
|
+
steps: `prompts create` requires prompt write access, while `prompts label`
|
|
287
|
+
requires prompt management access.
|
|
288
|
+
|
|
289
|
+
`api` accepts only operation IDs with an explicit handler compiled into this
|
|
290
|
+
CLI release. `--param` and `--query` accept bounded `name=value` pairs, reject
|
|
291
|
+
duplicates, and are checked against that operation's embedded parameter
|
|
292
|
+
allowlist before any request. Body-bearing safe reads accept one object from
|
|
293
|
+
`--body-stdin`, bounded to 64 KiB and validated against the embedded request
|
|
294
|
+
schema before any request. `schema` commands are offline and do not require credentials.
|
|
295
|
+
`schema list` and `schema search` return concise descriptors. `schema show`
|
|
296
|
+
returns the normalized embedded operation contract, including request and
|
|
297
|
+
response schemas, authentication requirements, and execution/risk metadata.
|
|
298
|
+
New schema operations default to non-executable until an explicit handler and
|
|
299
|
+
risk classification are added.
|
|
300
|
+
|
|
301
|
+
Raw `api` execution fails closed for operations that require target-specific
|
|
302
|
+
destructive confirmation. Use the operation's curated command instead; raw
|
|
303
|
+
execution intentionally has no generic `--confirm` flag because confirmation
|
|
304
|
+
bindings differ by resource.
|
|
305
|
+
|
|
306
|
+
Feedback and webhook bodies use bounded stdin so comments, expected responses,
|
|
307
|
+
destination URLs, and write-only webhook secrets do not appear in process
|
|
308
|
+
arguments. Integration status is local and redacted; it does not discover
|
|
309
|
+
providers, decrypt credentials, or contact external services.
|
|
310
|
+
|
|
311
|
+
Organization discovery is OAuth-only. Organization list requires
|
|
312
|
+
`context:read` plus current `org:read`; detail requires `organization:read`
|
|
313
|
+
plus current `org:read`. Project discovery accepts OAuth or service-account
|
|
314
|
+
tokens, requires `context:read` plus current `project:read`, and sends no
|
|
315
|
+
`x-project-id`. Legacy credentials and an explicitly selected project are
|
|
316
|
+
rejected locally for all discovery commands.
|
|
317
|
+
|
|
318
|
+
Account profile and notification-preference reads are OAuth-only and require
|
|
319
|
+
`profile:read`. Profile ignores a globally configured project and never sends
|
|
320
|
+
`x-project-id`; it exposes `avatarConfigured`, never an avatar URL. Notification
|
|
321
|
+
preferences require `--project` or `NEATLOGS_PROJECT_ID`, bind the current user
|
|
322
|
+
to that selected project, and print all channel, digest, Slack-DM, and
|
|
323
|
+
quiet-hours settings. Service-account and legacy credentials are rejected
|
|
324
|
+
locally before a request.
|
|
325
|
+
|
|
326
|
+
Saved-filter reads are OAuth-only and require a selected project,
|
|
327
|
+
`observability:read`, and current `trace:read`. Lists omit filter criteria;
|
|
328
|
+
detail returns only the caller-owned, project-bound filter tree. Trees are
|
|
329
|
+
bounded to 8 group levels, 100 total nodes, and 256 KiB. Opaque list cursors
|
|
330
|
+
bind the operation, selected project, OAuth actor, and normalized list filters.
|
|
331
|
+
|
|
332
|
+
Organization-access reads are also OAuth-only, forbid project selection, and
|
|
333
|
+
require `organization:read` plus the caller's current `member:read` permission.
|
|
334
|
+
Member responses expose only safe identity and active-membership fields.
|
|
335
|
+
Invitation pages omit tokens and accepted invitations, default to `pending`, and
|
|
336
|
+
can filter pending or expired rows. Role results are action-specific assignment
|
|
337
|
+
options; ownership transfer is not exposed.
|
|
338
|
+
|
|
339
|
+
Invitation mutations are OAuth-only, forbid project selection, and reuse a
|
|
340
|
+
stable idempotency key for retries. Invite accepts only generated assignable
|
|
341
|
+
roles. Resend and revoke bind both the organization and exact invitation UUID;
|
|
342
|
+
revoke additionally requires repeating that UUID with `--confirm`. Acceptance
|
|
343
|
+
reads the confidential token only from bounded non-interactive stdin via
|
|
344
|
+
`--token-stdin`; the token is never accepted as an argument or option value and
|
|
345
|
+
is not emitted in CLI output or diagnostics.
|
|
346
|
+
|
|
347
|
+
Alert-rule reads accept OAuth users and project-bound service accounts with
|
|
348
|
+
`configuration:read`, current `alert:read`, and an exact selected project.
|
|
349
|
+
`alerts list` returns bounded summaries with an opaque cursor; `alerts get`
|
|
350
|
+
returns typed rule configuration plus only a channel-presence mask. Neither
|
|
351
|
+
command exposes destination IDs, webhook configuration, creator identity,
|
|
352
|
+
tenant IDs, nor the internal property-filter DSL. Detail reports explicit
|
|
353
|
+
description/condition truncation flags and the original condition count.
|
|
354
|
+
`alerts history` reads a maximum 30-day fire window with an optional rule
|
|
355
|
+
filter, signed cursor, five bounded sample trace IDs, delivery-kind allowlist,
|
|
356
|
+
and truncation counts; it excludes private rule-change history, payloads,
|
|
357
|
+
destination identifiers, project IDs, actor data, and breaching span IDs.
|
|
358
|
+
`alerts changes` reads a rule's privacy-safe change audit, including after soft
|
|
359
|
+
deletion. It returns only strict change types, allowlisted public field names,
|
|
360
|
+
and bounded redaction counts; actor identity and raw before/after values are
|
|
361
|
+
never returned.
|
|
362
|
+
|
|
363
|
+
Detection read commands validate UUIDs, page bounds, status, path
|
|
364
|
+
parameters, response size, and the generated response schema before emitting
|
|
365
|
+
output. Their server operations accept OAuth or service-account tokens and
|
|
366
|
+
require a selected project plus `configuration:read` and `detection:read`; a
|
|
367
|
+
service account must also have an active binding to that project.
|
|
368
|
+
Lists return compact summaries and an opaque `nextCursor` when another page is
|
|
369
|
+
available. Pass that value unchanged with `--cursor`; page size may change
|
|
370
|
+
between requests. `detections get` returns the typed detector
|
|
371
|
+
configuration under a 768 KiB server budget and a 1 MiB client ceiling.
|
|
372
|
+
`detections history` returns created/updated/toggled/deleted events with only
|
|
373
|
+
the actor category and an allowlisted changed-field list. It never returns
|
|
374
|
+
user IDs, email addresses, service-account IDs, or before/after diff values.
|
|
375
|
+
Detection-result commands use the data-plane authorization boundary instead:
|
|
376
|
+
`observability:read` plus current `trace:read`. `detections hits` returns only
|
|
377
|
+
bounded trace/span references and scores, never detector metadata or trace
|
|
378
|
+
payloads, and uses a signed project-and-detection-bound cursor. `detections
|
|
379
|
+
trends` accepts a maximum 90-day window and returns UTC hour/day/week buckets.
|
|
380
|
+
|
|
381
|
+
With the server mutation gate enabled, managed detection commands are:
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
neatlogs detections create --group <group-id> --name "PII" --type pii --config '{"entities":["EMAIL_ADDRESS"]}'
|
|
385
|
+
neatlogs detections update <detection-id> --threshold 0.8
|
|
386
|
+
neatlogs detections disable <detection-id>
|
|
387
|
+
neatlogs detections enable <detection-id>
|
|
388
|
+
neatlogs detections delete <detection-id> --confirm <detection-id>
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Create/update validate bounded type-specific JSON on the server, require
|
|
392
|
+
`configuration:write`, current `detection:manage`, an exact selected project,
|
|
393
|
+
and an idempotency key. The CLI generates a UUID unless a retry deliberately
|
|
394
|
+
reuses `--idempotency-key`. Enable/disable set the desired state rather than
|
|
395
|
+
toggling, so replay is safe. Delete is non-interactive, requires the exact ID
|
|
396
|
+
twice, and refuses while any live ID-bound or legacy name-bound alert rule
|
|
397
|
+
depends on the detection. Configuration changes invalidate prior results and
|
|
398
|
+
schedule a backfill after the transaction commits.
|
|
399
|
+
|
|
400
|
+
Detection-group catalog commands are `groups list` and `groups get`. With the
|
|
401
|
+
server mutation gate enabled, `groups create --name`, `groups update <id>
|
|
402
|
+
--name`, and `groups delete <id> --confirm <id>` provide managed-group parity.
|
|
403
|
+
Create/update/delete accept an optional `--idempotency-key`; otherwise the CLI
|
|
404
|
+
generates a fresh UUID. Delete is non-interactive and requires the exact group
|
|
405
|
+
ID twice, which is safe for coding agents and CI. These operations require
|
|
406
|
+
`configuration:write`, current `detection:manage`, and a selected project; an
|
|
407
|
+
OAuth user or project-bound service account may call them.
|
|
408
|
+
|
|
409
|
+
Evaluation commands accept OAuth or service-account tokens. They require a
|
|
410
|
+
selected project, `evaluation:read`, and current `eval:read`; a service account
|
|
411
|
+
must also have an active binding to that project. Lists are
|
|
412
|
+
compact and project-scoped; `evals get` returns the bounded evaluation
|
|
413
|
+
configuration under a 512 KiB server budget and the same 1 MiB client ceiling.
|
|
414
|
+
Progress uses one tenant-scoped database snapshot. Item commands expose bounded
|
|
415
|
+
metadata only—not trace payloads, forms, answers, evaluator identity, or
|
|
416
|
+
internal revision fields—and item pages have a 768 KiB server ceiling.
|
|
417
|
+
`evals form get` returns only the current bounded question projection. With the
|
|
418
|
+
mutation gate enabled, a creator can use `evals form set --body-stdin` to append
|
|
419
|
+
and activate an immutable draft-form version; internal evaluator assignments
|
|
420
|
+
and AI verdict keys are never exposed. Replacement is human-evaluation-only and
|
|
421
|
+
returns a conflict when current questions carry private evaluator routing or AI
|
|
422
|
+
verdict metadata, preventing a read/edit/write cycle from widening access.
|
|
423
|
+
|
|
424
|
+
The evaluation creator can launch an existing-trace human evaluation and assign
|
|
425
|
+
it to themselves:
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
neatlogs evals launch '<evaluation-uuid>' --assign-me --review-duration 7d
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
This OAuth-user-only action requires creator ownership and sends no email or
|
|
432
|
+
Slack notification; the assignment remains available in the NeatLogs app.
|
|
433
|
+
|
|
434
|
+
Assigned-review discovery and reads are OAuth-only because an assignment belongs
|
|
435
|
+
to a real user. Draft and submit additionally require `evaluation:write`,
|
|
436
|
+
current `eval:submit`, and `PUBLIC_API_MUTATIONS_ENABLED=true` on the server.
|
|
437
|
+
The CLI reads a bounded JSON object from stdin and creates a high-entropy
|
|
438
|
+
idempotency key unless `--idempotency-key` is supplied for a deliberate retry.
|
|
439
|
+
If an automatically generated key reaches an ambiguous timeout, network, or
|
|
440
|
+
server-contract failure, the CLI prints that non-secret UUID in its diagnostic;
|
|
441
|
+
reuse it with `--idempotency-key` instead of minting a new mutation.
|
|
442
|
+
The same key and same request replay the stored result; reusing a key for a
|
|
443
|
+
different body fails with `IDEMPOTENCY_KEY_CONFLICT`. Service accounts cannot
|
|
444
|
+
impersonate a human reviewer.
|
|
445
|
+
|
|
446
|
+
Reusable evaluator definitions use `evaluators list|get|create|update|archive|
|
|
447
|
+
restore|duplicate`. Reads require `evaluation:read` and current `eval:read`;
|
|
448
|
+
writes require `evaluation:write`, current `eval:manage`, and the server
|
|
449
|
+
mutation gate. Create/update accept bounded JSON only through `--body-stdin`,
|
|
450
|
+
so prompts and tool configuration do not appear in shell history. Tool config
|
|
451
|
+
is write-only and is never printed; detail output reports only whether each
|
|
452
|
+
grant is configured. Archive/restore are explicit state-setting patches, and
|
|
453
|
+
duplicate atomically copies the definition, hidden grant configuration, and
|
|
454
|
+
pinned skills under a new non-conflicting name.
|
|
455
|
+
|
|
456
|
+
Trace/session commands accept legacy registry-v2 keys, OAuth, or service-account
|
|
457
|
+
tokens. OAuth/service-account credentials require a selected project; a legacy
|
|
458
|
+
key uses its bound project and may omit one. All require `observability:read`
|
|
459
|
+
and current `trace:read`. Search is bounded to 30 days and 16 terms; keyword and semantic
|
|
460
|
+
pagination uses actor/project/query-bound opaque snapshots. Raw previews are
|
|
461
|
+
byte-capped. `traces payload` requires a unique explicit field allowlist and
|
|
462
|
+
never returns object-storage locations or presigned URLs.
|
|
463
|
+
Search results expose at most 20 matched span identities per trace and only
|
|
464
|
+
their ID, name, and type. Trace/session exports support bounded JSON, Markdown,
|
|
465
|
+
and CSV. Human terminal output prints Markdown/CSV directly; `--json` preserves
|
|
466
|
+
the response envelope for pipelines. Export composition uses public projections
|
|
467
|
+
only and excludes raw payloads, private attributes, snippets, and S3 locations.
|
|
468
|
+
|
|
469
|
+
Guest-link and trace-sharing reads accept OAuth or service-account tokens,
|
|
470
|
+
require a selected project, `sharing:read`, and current `sharing:read`. They do
|
|
471
|
+
not accept legacy keys. Responses expose only bounded metadata and state—never
|
|
472
|
+
guest tokens, token hashes, public URLs or IDs, recipient email, creator
|
|
473
|
+
identity, or tenant identifiers. `guest-links list` cursors bind the operation,
|
|
474
|
+
selected project, and authenticated actor.
|
|
475
|
+
|
|
476
|
+
Guest-link mint requires `--recipient-email <email>`, normalizes the recipient,
|
|
477
|
+
and reveals the opaque token once. Rotation preserves the recipient and reveals
|
|
478
|
+
only the replacement token; metadata reads never reread either token. Guest
|
|
479
|
+
review uses no stored credential, profile, selected project, or environment
|
|
480
|
+
token. The capability token and request must arrive together as strict JSON on
|
|
481
|
+
stdin:
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
printf '%s' '{"token":"<guest-token>"}' |
|
|
485
|
+
neatlogs guest context --request-stdin
|
|
486
|
+
|
|
487
|
+
printf '%s' '{"token":"<guest-token>","answers":[{"questionId":"<question-uuid>","answerValue":"yes"}]}' |
|
|
488
|
+
neatlogs guest submit '<item-uuid>' --request-stdin
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Context accepts 1–25 items per page (default 25), at most 100 questions, 16 KiB
|
|
492
|
+
UTF-8 input and output previews with truncation flags, and a 1 MiB final
|
|
493
|
+
envelope. Submission accepts at most 100 distinct answers, 32 KiB per answer,
|
|
494
|
+
and 64 KiB raw JSON. It performs full answer replacement, including clearing
|
|
495
|
+
omitted optional answers. The CLI generates a high-entropy idempotency key
|
|
496
|
+
unless the caller supplies one for an intentional retry. Expired or revoked
|
|
497
|
+
tokens fail on fresh execution and replay. The generic `neatlogs api` executor
|
|
498
|
+
cannot run guest operations. Browser guest routes remain compatible because
|
|
499
|
+
they use the same context and submission services.
|
|
500
|
+
|
|
501
|
+
Credential inventory commands accept OAuth or service-account tokens, require
|
|
502
|
+
the selected project's current `api_key:read` permission plus `access:read`,
|
|
503
|
+
and reject legacy keys as callers. `api-keys list` reports safe Public API key
|
|
504
|
+
prefix metadata and whether the broad legacy project key is configured.
|
|
505
|
+
`ingest-credentials list` reports dedicated prefix/last-four hints and, for an
|
|
506
|
+
OAuth caller only, whether that caller has a legacy personal write key for the
|
|
507
|
+
selected organization. Neither command can reread plaintext or verifier hashes.
|
|
508
|
+
|
|
509
|
+
MCP and coding-tool status commands are OAuth-user-only, require a selected
|
|
510
|
+
project and `configuration:read`, and apply current `mcp:use` or `tool:use`
|
|
511
|
+
RBAC. MCP status also enforces the organization's plan entitlement. Responses
|
|
512
|
+
contain only aggregate configuration/run state; they never contain stored
|
|
513
|
+
tokens, URLs, headers, prompts, repositories, provider IDs, task IDs, or error
|
|
514
|
+
messages. Service-account and legacy credentials are rejected locally before a
|
|
515
|
+
request.
|
|
516
|
+
|
|
517
|
+
## Configuration and output
|
|
518
|
+
|
|
519
|
+
- `NEATLOGS_TOKEN` is the primary credential source; `NEATLOGS_API_KEY` is the
|
|
520
|
+
legacy fallback. An environment credential takes precedence over a selected
|
|
521
|
+
stored profile and is identified as `environment` by `auth status`.
|
|
522
|
+
- `--profile <name>` selects non-secret host/project preferences and its
|
|
523
|
+
separately stored OAuth credential. Stored tokens are never sent when a
|
|
524
|
+
`--host` or `NEATLOGS_HOST` override differs from the credential-bound host.
|
|
525
|
+
- Expiring OAuth access tokens are refreshed before an API request. Refresh
|
|
526
|
+
rotation is persisted back to the same credential store. Normal logout first
|
|
527
|
+
revokes the refresh family on the server and only then deletes the local
|
|
528
|
+
secret; `--local-only` is an explicit recovery escape hatch.
|
|
529
|
+
- Product reads and selected-project context commands require `--project
|
|
530
|
+
<uuid>` or `NEATLOGS_PROJECT_ID` for OAuth/service-account credentials.
|
|
531
|
+
`--project` takes precedence. A project is optional for legacy credentials.
|
|
532
|
+
Discovery commands instead forbid any selected project.
|
|
533
|
+
- A service-account token is sent only as `Authorization: Bearer` and the
|
|
534
|
+
selected project only as `x-project-id`. A legacy key is sent only as
|
|
535
|
+
`x-api-key`.
|
|
536
|
+
- `--host <origin>` overrides `NEATLOGS_HOST`. One of them is required for
|
|
537
|
+
online commands; the CLI never guesses a deployment domain. Offline `schema`
|
|
538
|
+
commands require neither.
|
|
539
|
+
- Hosts must be HTTPS origins with no path, user information, query, or hash.
|
|
540
|
+
- Browser PKCE is the default login. `--device` is the explicit fallback for a
|
|
541
|
+
remote/headless terminal. Both request reviewed OAuth scopes; current RBAC is
|
|
542
|
+
still evaluated by the server for every API request.
|
|
543
|
+
- `--json` or non-TTY stdout produces stable JSON. Data uses stdout and
|
|
544
|
+
diagnostics use stderr.
|
|
545
|
+
- Requests time out after 10 seconds and never follow redirects.
|
|
546
|
+
- Idempotent GET requests and explicitly marked safe POST reads retry at most
|
|
547
|
+
twice after a `429` or `503`, honoring a safe, bounded `Retry-After` value.
|
|
548
|
+
- Idempotent mutating operations retry at most twice after a `429` or `503`.
|
|
549
|
+
Other mutating operations are never retried.
|
|
550
|
+
|
|
551
|
+
## Guarded live-local context and organization-access smoke
|
|
552
|
+
|
|
553
|
+
This developer-only smoke packs the CLI, uses the exact current worktree
|
|
554
|
+
backend, exercises context discovery, saved filters, organization
|
|
555
|
+
member/invitation/role reads, and all three guest-link/sharing reads, and
|
|
556
|
+
creates short-lived fixtures only in the local Docker PostgreSQL database. It
|
|
557
|
+
never targets staging or production.
|
|
558
|
+
|
|
559
|
+
The command verifies generated API assets and rebuilds the distributable before
|
|
560
|
+
packing, so the exercised binary cannot lag behind the current source/spec.
|
|
561
|
+
|
|
562
|
+
Prerequisites:
|
|
563
|
+
|
|
564
|
+
- the worktree backend is listening on `127.0.0.1:4100` in `development` mode,
|
|
565
|
+
with local PostgreSQL and Redis configuration;
|
|
566
|
+
- local PostgreSQL is `neatlogs` on `127.0.0.1:5432` as role `neatlogs`;
|
|
567
|
+
- `psql`, `openssl`, `lsof`, `git`, Node, pnpm, and npm are available; and
|
|
568
|
+
- the backend listener PID and current 40-character worktree HEAD are supplied
|
|
569
|
+
explicitly. The smoke verifies the listener PID, backend working directory,
|
|
570
|
+
HEAD, and `/health` environment before fixture writes.
|
|
571
|
+
|
|
572
|
+
```bash
|
|
573
|
+
cd /path/to/neatlogs-app-worktree/cli
|
|
574
|
+
RUN_NEATLOGS_CLI_LIVE_LOCAL=1 \
|
|
575
|
+
NEATLOGS_LIVE_LOCAL_BACKEND_PID="$(lsof -nP -iTCP:4100 -sTCP:LISTEN -t)" \
|
|
576
|
+
NEATLOGS_LIVE_LOCAL_EXPECTED_HEAD="$(git -C .. rev-parse HEAD)" \
|
|
577
|
+
pnpm smoke:context-discovery:live-local
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
The HTTPS loopback proxy trusts only its generated loopback certificate through
|
|
581
|
+
the packed CLI child's `NODE_EXTRA_CA_CERTS`; TLS verification is never
|
|
582
|
+
disabled. External commands and network operations have deadlines. The smoke
|
|
583
|
+
waits for every successful request's audit row to become durable, deletes only
|
|
584
|
+
its exact request IDs/fixture IDs/marker, and requires zero residue. Signals
|
|
585
|
+
abort active work and unwind normal cleanup, including the packed-consumer and
|
|
586
|
+
certificate temporary directories.
|
|
587
|
+
|
|
588
|
+
## Exit codes
|
|
589
|
+
|
|
590
|
+
| Code | Meaning |
|
|
591
|
+
| ---: | -------------------------------------------- |
|
|
592
|
+
| 0 | Success |
|
|
593
|
+
| 2 | Invalid arguments, configuration, or request |
|
|
594
|
+
| 3 | Authentication is missing or invalid |
|
|
595
|
+
| 4 | Authorization or scope denied |
|
|
596
|
+
| 5 | Resource not found |
|
|
597
|
+
| 6 | Conflict |
|
|
598
|
+
| 7 | Rate limited or temporarily unavailable |
|
|
599
|
+
| 8 | Network, TLS, timeout, or redirect failure |
|
|
600
|
+
| 9 | Partial bulk-operation success |
|
|
601
|
+
| 10 | Destructive confirmation required |
|
|
602
|
+
| 11 | Server or response-contract failure |
|