ninchi-cli 0.2.0__tar.gz → 0.2.1__tar.gz
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.
- ninchi_cli-0.2.1/PKG-INFO +443 -0
- ninchi_cli-0.2.1/README.md +418 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/pyproject.toml +1 -1
- ninchi_cli-0.2.1/src/ninchi_cli/__init__.py +14 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/src/ninchi_cli/client.py +19 -2
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/src/ninchi_cli/main.py +32 -2
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/src/ninchi_cli/mcp_server.py +3 -1
- ninchi_cli-0.2.1/src/ninchi_cli.egg-info/PKG-INFO +443 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/tests/test_client.py +29 -0
- ninchi_cli-0.2.1/tests/test_main.py +423 -0
- ninchi_cli-0.2.0/PKG-INFO +0 -138
- ninchi_cli-0.2.0/README.md +0 -113
- ninchi_cli-0.2.0/src/ninchi_cli/__init__.py +0 -5
- ninchi_cli-0.2.0/src/ninchi_cli.egg-info/PKG-INFO +0 -138
- ninchi_cli-0.2.0/tests/test_main.py +0 -65
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/setup.cfg +0 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/src/ninchi_cli/config.py +0 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/src/ninchi_cli/diffs.py +0 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/src/ninchi_cli.egg-info/SOURCES.txt +0 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/src/ninchi_cli.egg-info/dependency_links.txt +0 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/src/ninchi_cli.egg-info/entry_points.txt +0 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/src/ninchi_cli.egg-info/requires.txt +0 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/src/ninchi_cli.egg-info/top_level.txt +0 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/tests/test_config.py +0 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/tests/test_diffs.py +0 -0
- {ninchi_cli-0.2.0 → ninchi_cli-0.2.1}/tests/test_mcp_server.py +0 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ninchi-cli
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Command-line client and MCP server for Ninchi checks
|
|
5
|
+
Author-email: Ninchi <support@ninchi.ai>
|
|
6
|
+
License: Proprietary
|
|
7
|
+
Project-URL: Homepage, https://ninchi.ai
|
|
8
|
+
Project-URL: Documentation, https://ninchi.ai/docs/cli
|
|
9
|
+
Keywords: ninchi,code-review,verification,mcp,cli
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: Other/Proprietary License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
22
|
+
Requires-Dist: mcp<2,>=1.2
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest<9,>=8; extra == "dev"
|
|
25
|
+
|
|
26
|
+
# Ninchi CLI and MCP server
|
|
27
|
+
|
|
28
|
+
Run Ninchi checks from a terminal, Git hook, CI job, or MCP-capable editor.
|
|
29
|
+
The package is a thin HTTP client: it does not import the Ninchi backend or
|
|
30
|
+
question engine.
|
|
31
|
+
|
|
32
|
+
A programmatic check records evidence of demonstrated understanding tied to
|
|
33
|
+
the submitted artifact. It is a separate evidence class from pull-request
|
|
34
|
+
verification, not a measurement of latent ability, mastery, or competency.
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
Install the published package from PyPI:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pipx install ninchi-cli
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Use `ninchi-cli` 0.2.1 or later. Version 0.2.0 predates an API change in how
|
|
45
|
+
a check reports that its question is still being generated. Against the
|
|
46
|
+
current API, 0.2.0 shows an empty question instead of waiting for it. Check
|
|
47
|
+
the installed version with `pipx list` and upgrade with
|
|
48
|
+
`pipx upgrade ninchi-cli`.
|
|
49
|
+
|
|
50
|
+
### Development install from a checkout
|
|
51
|
+
|
|
52
|
+
From the repository root:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pipx install ./cli
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For editable development with test dependencies:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
cd cli
|
|
62
|
+
python3.12 -m venv .venv
|
|
63
|
+
.venv/bin/pip install -e ".[dev]"
|
|
64
|
+
.venv/bin/pytest -q
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The package requires Python 3.11 or newer.
|
|
68
|
+
|
|
69
|
+
## PATH and GUI editors
|
|
70
|
+
|
|
71
|
+
After the verified public `pipx install ...` command:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pipx ensurepath
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Close and reopen the shell, then verify:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
command -v ninchi
|
|
81
|
+
ninchi --help
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If an MCP client reports the literal error `spawn ninchi ENOENT`, it cannot
|
|
85
|
+
find the executable. GUI editors often do not inherit the PATH used by an
|
|
86
|
+
interactive shell. Run `command -v ninchi` (or `which ninchi`) in a terminal
|
|
87
|
+
and use the printed absolute path in the MCP configuration.
|
|
88
|
+
|
|
89
|
+
## Prerequisites
|
|
90
|
+
|
|
91
|
+
GitHub is not required. A check is submitted directly to an organization. It
|
|
92
|
+
needs no repository, pull request, or source-control connection.
|
|
93
|
+
|
|
94
|
+
1. Have a Ninchi account. Any sign-in method works: email and password
|
|
95
|
+
(with optional TOTP MFA), your organization's SAML single sign-on, or a
|
|
96
|
+
GitHub, GitLab, or Bitbucket account.
|
|
97
|
+
2. Join the target Ninchi organization. To start an organization without a
|
|
98
|
+
source-control connection, create a **Direct** organization at
|
|
99
|
+
`/dashboard/create-org` and invite members by email. GitHub, GitLab, and
|
|
100
|
+
Bitbucket organizations work the same way for programmatic checks.
|
|
101
|
+
3. Find its ID in the dashboard URL — the segment after `/dashboard/orgs/`.
|
|
102
|
+
Both identifier forms work: a numeric id (`/dashboard/orgs/42` →
|
|
103
|
+
`--org-id 42`) or the org's opaque UUID
|
|
104
|
+
(`/dashboard/orgs/1b671a64-…` → `--org-id 1b671a64-…`). New dashboard
|
|
105
|
+
URLs use the UUID form; numeric ids in existing configs keep working
|
|
106
|
+
indefinitely. The CLI does not currently have an org-list command.
|
|
107
|
+
4. Ask an org admin to open org settings, choose the **Challenges** tab, find
|
|
108
|
+
the **Programmatic Checks (CLI & MCP)** card, and turn on **Enable CLI &
|
|
109
|
+
MCP check submission**. The same card sets **Answers submitted by AI
|
|
110
|
+
agents**, which defaults to blocked (see [Answering-actor
|
|
111
|
+
semantics](#answering-actor-semantics)).
|
|
112
|
+
5. Make sure the organization's plan includes programmatic checks. The
|
|
113
|
+
Hobbyist / Free plan has a quota of zero, including for a new Direct
|
|
114
|
+
organization.
|
|
115
|
+
|
|
116
|
+
Programmatic checks have a hard quota per developer per org in a trailing
|
|
117
|
+
30-day window. The limit comes from the org's plan, and checks you submit to
|
|
118
|
+
one org do not count against another org's quota. A developer who belongs to
|
|
119
|
+
two orgs has a separate allowance in each.
|
|
120
|
+
|
|
121
|
+
| Plan | Checks per developer, per org |
|
|
122
|
+
|---|---:|
|
|
123
|
+
| Hobbyist / Free | 0 |
|
|
124
|
+
| Standard | 20 |
|
|
125
|
+
| Pro | 100 |
|
|
126
|
+
| Enterprise | 100+ (operator-configured, never below 100) |
|
|
127
|
+
|
|
128
|
+
When the quota is exhausted, the API returns HTTP 429. On a plan that allows
|
|
129
|
+
some checks, the response also states the UTC time when the next check becomes
|
|
130
|
+
available. At that time, enough checks have left the window to make room for
|
|
131
|
+
another check. A plan downgrade can leave you above the cap. Several checks
|
|
132
|
+
must then leave the window, and the stated time moves later.
|
|
133
|
+
|
|
134
|
+
A zero-allowance plan never frees a slot, so the response carries no reset
|
|
135
|
+
time. Waiting does not help. The org needs a plan with a quota above zero.
|
|
136
|
+
|
|
137
|
+
## Authentication
|
|
138
|
+
|
|
139
|
+
### Device login
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
ninchi login
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The CLI:
|
|
146
|
+
|
|
147
|
+
1. prints a verification URL and a code such as `XXXX-XXXX`;
|
|
148
|
+
2. waits while you sign in and approve the code at `/dashboard/device`; and
|
|
149
|
+
3. saves the issued personal access token to
|
|
150
|
+
`~/.config/ninchi/credentials`.
|
|
151
|
+
|
|
152
|
+
The credentials file is mode `0600`; its parent directory is mode `0700`.
|
|
153
|
+
`NINCHI_CONFIG_DIR` overrides the directory. Otherwise the CLI honors
|
|
154
|
+
`XDG_CONFIG_HOME` before falling back to `~/.config/ninchi`.
|
|
155
|
+
|
|
156
|
+
Login flags:
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
--timeout SECONDS approval timeout (default: 600)
|
|
160
|
+
--api-url URL API override (default: https://api.ninchi.ai)
|
|
161
|
+
--json machine-readable output
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### CI token
|
|
165
|
+
|
|
166
|
+
CI should use an environment variable rather than the credentials file:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
export NINCHI_API_TOKEN="ninchi_pat_..."
|
|
170
|
+
export NINCHI_ORG_ID=42
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Create and revoke PATs at `/dashboard/profile`. A token is shown once, is
|
|
174
|
+
stored by Ninchi as an HMAC-SHA256 digest, and stops working immediately after
|
|
175
|
+
revocation. The available scopes are:
|
|
176
|
+
|
|
177
|
+
- `checks:read` — read challenges, results, and personal history.
|
|
178
|
+
- `checks:write` — submit checks and answers.
|
|
179
|
+
|
|
180
|
+
Device login requests both scopes by default. Manually created tokens also
|
|
181
|
+
default to both scopes.
|
|
182
|
+
|
|
183
|
+
`NINCHI_API_URL` or `--api-url` can target another API environment.
|
|
184
|
+
|
|
185
|
+
## CLI usage
|
|
186
|
+
|
|
187
|
+
### `ninchi check`
|
|
188
|
+
|
|
189
|
+
With no source flag, `check` submits the working-tree diff from
|
|
190
|
+
`git diff HEAD`:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
ninchi check --org-id 42
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Choose exactly one alternate subject source:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
git diff | ninchi check --stdin --org-id 42
|
|
200
|
+
ninchi check --staged --org-id 42
|
|
201
|
+
ninchi check --commit HEAD --org-id 42
|
|
202
|
+
ninchi check --file src/app.py --language python --org-id 42
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Set the org once for subsequent commands:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
export NINCHI_ORG_ID=42
|
|
209
|
+
ninchi check --staged
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
All `check` flags:
|
|
213
|
+
|
|
214
|
+
```text
|
|
215
|
+
--stdin
|
|
216
|
+
--staged
|
|
217
|
+
--commit SHA
|
|
218
|
+
--file PATH
|
|
219
|
+
--language LANGUAGE
|
|
220
|
+
--org-id ID
|
|
221
|
+
--answer TEXT
|
|
222
|
+
--actor human_attested|agent_assisted|agent_autonomous
|
|
223
|
+
--poll-interval SECONDS
|
|
224
|
+
--timeout SECONDS
|
|
225
|
+
--api-url URL
|
|
226
|
+
--json
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
`--language` is a hint for `--file`. `--poll-interval` defaults to 2 seconds;
|
|
230
|
+
`--timeout` defaults to 600 seconds.
|
|
231
|
+
|
|
232
|
+
Automation can answer non-interactively and emit JSON:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
ninchi check --staged \
|
|
236
|
+
--answer "$ANSWER" \
|
|
237
|
+
--actor agent_assisted \
|
|
238
|
+
--json
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
If `--json` is used without `--answer`, the CLI returns the generated
|
|
242
|
+
challenge and exits 2 with guidance to pass an answer.
|
|
243
|
+
|
|
244
|
+
### Answering-actor semantics
|
|
245
|
+
|
|
246
|
+
- An answer typed interactively defaults to `human_attested`.
|
|
247
|
+
- `--answer`, or a process with no terminal, defaults to `agent_assisted`.
|
|
248
|
+
- `--actor` overrides the default. Use the value that honestly describes who
|
|
249
|
+
authored the answer:
|
|
250
|
+
- `human_attested`: the human wrote the answer.
|
|
251
|
+
- `agent_assisted`: a human meaningfully directed the answer's content.
|
|
252
|
+
- `agent_autonomous`: an agent authored the answer.
|
|
253
|
+
|
|
254
|
+
The server enforces the organization's agent-answer policy. Never relabel an
|
|
255
|
+
answer to bypass that policy.
|
|
256
|
+
|
|
257
|
+
### `ninchi result`
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
ninchi result CHALLENGE_ID
|
|
261
|
+
ninchi result CHALLENGE_ID --json
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### `ninchi history`
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
ninchi history
|
|
268
|
+
ninchi history --limit 50
|
|
269
|
+
ninchi history --limit 50 --json
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
The default limit is 20. The server accepts limits from 1 to 100.
|
|
273
|
+
|
|
274
|
+
### Exit codes
|
|
275
|
+
|
|
276
|
+
- `0`: challenge passed.
|
|
277
|
+
- `1`: challenge failed.
|
|
278
|
+
- `2`: pending state, configuration error, authentication error, API error, or
|
|
279
|
+
another operational error.
|
|
280
|
+
|
|
281
|
+
## Pre-push hook
|
|
282
|
+
|
|
283
|
+
Example `.git/hooks/pre-push`:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
#!/usr/bin/env bash
|
|
287
|
+
set -euo pipefail
|
|
288
|
+
|
|
289
|
+
base="${NINCHI_BASE_REF:-origin/main}"
|
|
290
|
+
git diff --patch "$base"...HEAD | ninchi check \
|
|
291
|
+
--stdin \
|
|
292
|
+
--org-id "${NINCHI_ORG_ID:?set NINCHI_ORG_ID}"
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Make it executable:
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
chmod +x .git/hooks/pre-push
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
This form is human-attested: it omits `--answer` and prompts in the terminal.
|
|
302
|
+
|
|
303
|
+
## CI
|
|
304
|
+
|
|
305
|
+
The CLI needs only two environment variables, `NINCHI_API_TOKEN` and
|
|
306
|
+
`NINCHI_ORG_ID`, so it runs in any CI system: GitLab CI, Bitbucket
|
|
307
|
+
Pipelines, Jenkins, and others. The GitHub Actions job below is one example.
|
|
308
|
+
The same pipeline works elsewhere: install with pipx, pipe the diff against
|
|
309
|
+
the target branch into `ninchi check --stdin --json`, and store the token as a
|
|
310
|
+
masked secret.
|
|
311
|
+
|
|
312
|
+
### GitHub Actions
|
|
313
|
+
|
|
314
|
+
```yaml
|
|
315
|
+
name: Ninchi check
|
|
316
|
+
on:
|
|
317
|
+
pull_request:
|
|
318
|
+
|
|
319
|
+
jobs:
|
|
320
|
+
ninchi:
|
|
321
|
+
runs-on: ubuntu-latest
|
|
322
|
+
steps:
|
|
323
|
+
- uses: actions/checkout@v4
|
|
324
|
+
with:
|
|
325
|
+
fetch-depth: 0
|
|
326
|
+
- uses: actions/setup-python@v5
|
|
327
|
+
with:
|
|
328
|
+
python-version: "3.12"
|
|
329
|
+
- run: pipx install ninchi-cli
|
|
330
|
+
- name: Submit Ninchi check and surface the challenge
|
|
331
|
+
run: |
|
|
332
|
+
git diff --patch origin/${{ github.base_ref }}...HEAD |
|
|
333
|
+
ninchi check --stdin --json | tee ninchi-challenge.json || true
|
|
334
|
+
env:
|
|
335
|
+
NINCHI_API_TOKEN: ${{ secrets.NINCHI_API_TOKEN }}
|
|
336
|
+
NINCHI_ORG_ID: ${{ vars.NINCHI_ORG_ID }}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Store the PAT in GitHub Secrets. This job stops at submission by design: with
|
|
340
|
+
`--json` and no `--answer`, the CLI prints the challenge JSON — including the
|
|
341
|
+
question — and exits 2 (the `|| true` keeps the step green). The answer must
|
|
342
|
+
come from whoever authored the change; do not wire a canned or scripted answer
|
|
343
|
+
into CI. The question is generated per submission, and the answer window (the
|
|
344
|
+
org-configured TTL) starts once the challenge is first viewed — so have authors
|
|
345
|
+
answer interactively where they work, such as the pre-push hook above or an
|
|
346
|
+
MCP-capable editor.
|
|
347
|
+
|
|
348
|
+
## MCP server (`ninchi mcp`)
|
|
349
|
+
|
|
350
|
+
Authenticate once with `ninchi login`, then configure the stdio server in an
|
|
351
|
+
MCP-capable client.
|
|
352
|
+
|
|
353
|
+
### Recommended: absolute path
|
|
354
|
+
|
|
355
|
+
Run:
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
command -v ninchi
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Use that output as `command`:
|
|
362
|
+
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"mcpServers": {
|
|
366
|
+
"ninchi": {
|
|
367
|
+
"command": "/absolute/path/from/command-v-ninchi",
|
|
368
|
+
"args": ["mcp"]
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Cursor accepts this shape in `.cursor/mcp.json` or its global MCP settings.
|
|
375
|
+
Other MCP clients use the same command and argument, though their config-file
|
|
376
|
+
location differs.
|
|
377
|
+
|
|
378
|
+
### Alternative when the editor inherits PATH
|
|
379
|
+
|
|
380
|
+
```json
|
|
381
|
+
{
|
|
382
|
+
"mcpServers": {
|
|
383
|
+
"ninchi": {
|
|
384
|
+
"command": "ninchi",
|
|
385
|
+
"args": ["mcp"]
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
If this produces `spawn ninchi ENOENT`, use the absolute-path form.
|
|
392
|
+
|
|
393
|
+
### Five MCP tools
|
|
394
|
+
|
|
395
|
+
| Tool | Purpose |
|
|
396
|
+
|---|---|
|
|
397
|
+
| `submit_check` | Submit exactly one diff, content block, or file region and start question generation. |
|
|
398
|
+
| `get_challenge` | Fetch the question, optionally waiting while generation finishes. |
|
|
399
|
+
| `submit_answer` | Submit an answer with a required, honest `actor` claim. |
|
|
400
|
+
| `get_result` | Fetch score and feedback, optionally waiting while evaluation finishes. |
|
|
401
|
+
| `list_history` | List the authenticated developer's recent challenges. |
|
|
402
|
+
|
|
403
|
+
`submit_answer` requires `actor`. When the org policy is `blocked`, the tool
|
|
404
|
+
returns guidance to hand the question to the human and relay only the human's
|
|
405
|
+
own words as `human_attested`. When the policy is `recorded`,
|
|
406
|
+
`agent_assisted` and `agent_autonomous` answers are accepted and stored with
|
|
407
|
+
that provenance.
|
|
408
|
+
|
|
409
|
+
MCP check submissions include:
|
|
410
|
+
|
|
411
|
+
```json
|
|
412
|
+
{
|
|
413
|
+
"client_attribution": "mcp:<client>"
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
This names the submitting channel and feeds AI-authorship analytics as a
|
|
418
|
+
detection-floor signal. It does not, by itself, assert that AI assisted the
|
|
419
|
+
submitted work. When the client name is unavailable, the server uses `mcp`.
|
|
420
|
+
|
|
421
|
+
## Evidence and score semantics
|
|
422
|
+
|
|
423
|
+
Programmatic checks use `origin="api"` and are stored as a distinct,
|
|
424
|
+
lower-weight evidence class. Their question, answer, score, artifact context,
|
|
425
|
+
answering-actor claim, client attribution, and timestamps remain inspectable.
|
|
426
|
+
|
|
427
|
+
By default, this evidence does **not** count toward Ninchi Scores. An org admin
|
|
428
|
+
may opt in with **Count programmatic checks toward Ninchi Scores** in the
|
|
429
|
+
Programmatic Checks card. Pull-request evidence is unaffected either way.
|
|
430
|
+
|
|
431
|
+
## Troubleshooting
|
|
432
|
+
|
|
433
|
+
| Symptom | Resolution |
|
|
434
|
+
|---|---|
|
|
435
|
+
| `spawn ninchi ENOENT` | The editor cannot find the executable. Run `pipx ensurepath`, open a new shell, run `command -v ninchi`, and use the resulting absolute path in the MCP config. |
|
|
436
|
+
| 403: programmatic checks are not enabled | An org admin must enable **Enable CLI & MCP check submission** in **Programmatic Checks (CLI & MCP)** on the **Challenges** tab of org settings. |
|
|
437
|
+
| 429 | The trailing-30-day quota for this developer in this org is exhausted. When the plan allows some checks, the response gives the UTC time the window next frees a slot. On a zero-allowance plan (Hobbyist / Free) there is no reset time to report; the org needs a plan that includes programmatic checks. |
|
|
438
|
+
| 403 on an agent answer | The org's `programmatic_agent_answers` policy is `blocked`. Hand the question to the human; submit only their own words as `human_attested`. |
|
|
439
|
+
| Challenge expired | The answer window starts when a ready challenge is first viewed. The org configures the TTL; the shipped default is 5 minutes. |
|
|
440
|
+
| Status `generating` or `answered` | Generation and grading are asynchronous. `generating` means the question is not ready; `answered` means grading is still running. Keep polling `get_challenge` or `get_result` until a terminal result or client timeout. The MCP tools report a timed-out wait as `generating` or `evaluating`. |
|
|
441
|
+
| Empty question, then an error on answer | You are running `ninchi-cli` 0.2.0, which does not wait for generation against the current API. Run `pipx upgrade ninchi-cli`. |
|
|
442
|
+
|
|
443
|
+
CLI errors are printed to stderr, or as JSON with `--json`, and exit 2.
|