copilotkit 4.26.0 → 4.28.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.
Files changed (92) hide show
  1. package/README.md +418 -40
  2. package/cli-build-info.json +7 -7
  3. package/index.js +15343 -9085
  4. package/onboarding/index.json +3 -2
  5. package/onboarding/prompts/authenticate/start.md +48 -56
  6. package/onboarding/prompts/conversion/plan.md +3 -3
  7. package/onboarding/prompts/credentials/finalize-plan.md +42 -29
  8. package/onboarding/prompts/credentials/plan.md +50 -34
  9. package/onboarding/prompts/credentials/settle-credentials.md +38 -14
  10. package/onboarding/prompts/credentials/write-plan.md +122 -47
  11. package/onboarding/prompts/deployment/choose-local.md +17 -20
  12. package/onboarding/prompts/deployment/local-evaluation.md +45 -21
  13. package/onboarding/prompts/fallback/best-effort.md +14 -16
  14. package/onboarding/prompts/feature/a2ui/implement.md +4 -4
  15. package/onboarding/prompts/feature/a2ui/plan.md +3 -3
  16. package/onboarding/prompts/feature/a2ui/proof.md +5 -5
  17. package/onboarding/prompts/feature/a2ui/start.md +10 -8
  18. package/onboarding/prompts/feature/channels/implement.md +11 -8
  19. package/onboarding/prompts/feature/channels/plan.md +15 -7
  20. package/onboarding/prompts/feature/channels/proof.md +8 -7
  21. package/onboarding/prompts/feature/channels/start.md +11 -10
  22. package/onboarding/prompts/feature/chat-suggestions/implement.md +4 -4
  23. package/onboarding/prompts/feature/chat-suggestions/plan.md +3 -3
  24. package/onboarding/prompts/feature/chat-suggestions/proof.md +5 -5
  25. package/onboarding/prompts/feature/chat-suggestions/start.md +10 -8
  26. package/onboarding/prompts/feature/complete.md +2 -2
  27. package/onboarding/prompts/feature/learning/implement.md +14 -12
  28. package/onboarding/prompts/feature/learning/plan.md +4 -4
  29. package/onboarding/prompts/feature/learning/proof.md +24 -14
  30. package/onboarding/prompts/feature/learning/start.md +8 -8
  31. package/onboarding/prompts/feature/open-generative-ui/implement.md +4 -4
  32. package/onboarding/prompts/feature/open-generative-ui/plan.md +3 -3
  33. package/onboarding/prompts/feature/open-generative-ui/proof.md +5 -5
  34. package/onboarding/prompts/feature/open-generative-ui/start.md +10 -8
  35. package/onboarding/prompts/feature/realtime-sync/implement.md +7 -5
  36. package/onboarding/prompts/feature/realtime-sync/plan.md +3 -3
  37. package/onboarding/prompts/feature/realtime-sync/proof.md +5 -5
  38. package/onboarding/prompts/feature/realtime-sync/start.md +7 -7
  39. package/onboarding/prompts/feature/rich-threads/implement.md +8 -6
  40. package/onboarding/prompts/feature/rich-threads/plan.md +3 -3
  41. package/onboarding/prompts/feature/rich-threads/proof.md +5 -5
  42. package/onboarding/prompts/feature/rich-threads/start.md +7 -7
  43. package/onboarding/prompts/feature/stop.md +4 -4
  44. package/onboarding/prompts/feature/voice/implement.md +4 -4
  45. package/onboarding/prompts/feature/voice/plan.md +4 -4
  46. package/onboarding/prompts/feature/voice/proof.md +5 -5
  47. package/onboarding/prompts/feature/voice/start.md +10 -8
  48. package/onboarding/prompts/framework/ag2.md +20 -5
  49. package/onboarding/prompts/framework/agno.md +25 -9
  50. package/onboarding/prompts/framework/built-in.md +21 -6
  51. package/onboarding/prompts/framework/claude-sdk-python.md +11 -5
  52. package/onboarding/prompts/framework/claude-sdk-typescript.md +13 -6
  53. package/onboarding/prompts/framework/crewai-flows.md +24 -10
  54. package/onboarding/prompts/framework/custom-ag-ui.md +62 -28
  55. package/onboarding/prompts/framework/deep-agents.md +26 -9
  56. package/onboarding/prompts/framework/google-adk.md +18 -5
  57. package/onboarding/prompts/framework/langgraph-fastapi.md +20 -5
  58. package/onboarding/prompts/framework/langgraph-python.md +20 -5
  59. package/onboarding/prompts/framework/langgraph-typescript.md +27 -7
  60. package/onboarding/prompts/framework/llamaindex.md +24 -8
  61. package/onboarding/prompts/framework/mastra.md +21 -8
  62. package/onboarding/prompts/framework/ms-agent-dotnet.md +24 -6
  63. package/onboarding/prompts/framework/ms-agent-harness-dotnet.md +24 -5
  64. package/onboarding/prompts/framework/ms-agent-python.md +21 -5
  65. package/onboarding/prompts/framework/pydantic-ai.md +20 -5
  66. package/onboarding/prompts/framework/strands-python.md +27 -12
  67. package/onboarding/prompts/framework/strands-typescript.md +27 -12
  68. package/onboarding/prompts/frontend/angular.md +4 -4
  69. package/onboarding/prompts/frontend/nextjs.md +4 -4
  70. package/onboarding/prompts/frontend/plan.md +21 -13
  71. package/onboarding/prompts/frontend/react-native.md +3 -3
  72. package/onboarding/prompts/frontend/react-spa.md +3 -3
  73. package/onboarding/prompts/frontend/vue.md +3 -3
  74. package/onboarding/prompts/implementation/build-and-validate.md +27 -20
  75. package/onboarding/prompts/proof/complete.md +9 -7
  76. package/onboarding/prompts/proof/oss-baseline.md +9 -6
  77. package/onboarding/prompts/proof/round-trip.md +18 -20
  78. package/onboarding/prompts/research/gather.md +38 -10
  79. package/onboarding/prompts/research/merge.md +3 -3
  80. package/onboarding/prompts/research/preflight.md +2 -2
  81. package/onboarding/prompts/research/route.md +10 -4
  82. package/onboarding/prompts/setup/questions.md +54 -202
  83. package/onboarding/prompts/starter/clone.md +141 -57
  84. package/onboarding/prompts/stopped/run-failed.md +5 -3
  85. package/onboarding/prompts/subagent/create-plan.md +73 -22
  86. package/onboarding/prompts/subagent/implement-and-validate.md +27 -34
  87. package/onboarding/prompts/subagent/inspect-repository.md +3 -2
  88. package/onboarding/prompts/subagent/prove-oss-baseline.md +10 -5
  89. package/onboarding/prompts/subagent/prove-round-trip.md +46 -54
  90. package/onboarding/prompts/unsupported/no-validated-path.md +5 -4
  91. package/package.json +1 -1
  92. package/release/release-tool.js +19 -2
package/README.md CHANGED
@@ -291,7 +291,10 @@ Under `--json`, the first `authentication_url` record is the URL with the code
291
291
  in it, and it also carries `user_code` and `expires_at`. A renewed code writes
292
292
  another `authentication_url` record, with `renewed: true` and its `renewal`
293
293
  number, and another `action_required` record. The old page then shows an
294
- expired code, so show the developer the new one. A sign-in that ends without a session writes a `failed`
294
+ expired code, so show the developer the new one. If an earlier `login` on this
295
+ machine stopped while its code was still valid, the next one reuses that code
296
+ instead of requesting a new one, and its `authentication_url` record carries
297
+ `resumed: true`. A sign-in that ends without a session writes a `failed`
295
298
  record with `reason: expired` or `reason: access_denied`, and with
296
299
  `retry: ask_developer`: a person must act before a new code can work. If a
297
300
  code expired and the request for its replacement failed, for example on a rate
@@ -323,10 +326,12 @@ Run `onboard start` in the project folder, or in an empty folder for a new app.
323
326
 
324
327
  `onboard start` is meant for a coding agent. If stdout is a terminal and the CLI
325
328
  detects no coding agent, it prints the agent prompt as usual and then a short
326
- note for a person. The note tells them to open their coding agent in the
327
- folder and paste the prompt that they copied. It also gives a line to paste
328
- that continues the same run. An agent that the CLI does not detect reads the
329
- full prompt above the note, so the note does not block it.
329
+ note for a person. Most such people came from a coding agent that asked them
330
+ to run the command. The note sends them back to that agent, or tells them to
331
+ open one in the folder, with a line to paste. The line tells the agent to run
332
+ the command itself, because it is not interactive, and continues the same run.
333
+ An agent that the CLI does not detect reads the full prompt above the note, so
334
+ the note does not block it.
330
335
 
331
336
  ### Where a run keeps its state
332
337
 
@@ -452,6 +457,10 @@ The fields:
452
457
  events do not have it. The total always has it when setup finished.
453
458
  - The total carries `duration_ms`, `outcome`, and `phase_count`. A failed setup adds
454
459
  `failed_setup_phase`.
460
+ - The total also carries `learning_model`: `configured` when the stack gets a Learning
461
+ model, or `deferred` when setup ran with `--defer-model` or "configure later". A resumed
462
+ setup reports the choice it saved. The total has no `learning_model` when setup stopped
463
+ before the choice was known, for example at the Docker check.
455
464
  - A failed setup also adds `failure_reason` to the total and to the failed phase. It is
456
465
  a fixed slug that comes from the error's type, never from its message. Examples:
457
466
  `docker_unavailable`, `authentication_required`, `memory_short`, `cpu_short`,
@@ -461,7 +470,7 @@ The fields:
461
470
  - `local setup` and `local update` check Docker before their progress starts. If that
462
471
  check fails, the CLI still sends a failed setup. Its `failed_setup_phase` is
463
472
  `docker-check`, and it carries a `failure_reason`.
464
- - On Ctrl-C or SIGTERM, the open phase and the total send `outcome: abandoned` before
473
+ - On Ctrl-C, SIGTERM, or SIGHUP, the open phase and the total send `outcome: abandoned` before
465
474
  the CLI exits. The total adds `abandoned_setup_phase` and the `bytes_downloaded` so
466
475
  far. The CLI waits at most 2 seconds for these sends, then exits with the signal's
467
476
  usual status.
@@ -1058,6 +1067,13 @@ is. The onboarding run keeps the choice for that directory only, so later
1058
1067
  `onboard credentials` and `onboard model-key` calls from there use `.env.local`
1059
1068
  without the flag, and calls from any other directory use `.env`.
1060
1069
 
1070
+ Once the project key is in a `.env.local` that git ignores and the app's runtime
1071
+ reads, beside a `.env` that git tracks, the CLI treats that file as your choice
1072
+ for the app. A new onboarding run,
1073
+ `license`, and `local connect` write there too, and none of them asks you to
1074
+ untrack `.env` again. The Channels setup commands still read and write `.env`
1075
+ only.
1076
+
1061
1077
  ## Onboarding backups and restore
1062
1078
 
1063
1079
  `copilotkit onboard start` backs up the project before the run changes anything.
@@ -1067,23 +1083,38 @@ It prints one line on stderr that names the run whose backup it is.
1067
1083
  untracked file, kept under the private ref `refs/copilotkit/backup/<run-id>`.
1068
1084
  The CLI builds it in a temporary index, so your index, working tree, branch and
1069
1085
  stash do not change. Env and credential files (`.env`, `.env.*`, `.dev.vars`,
1070
- `.envrc`, `credentials`, `*.tfvars`, `secrets.*`, `.npmrc`, `.pypirc`, `*.pem`,
1086
+ `.envrc`, `credentials`, `*.tfvars`, `*.tfstate`, `secrets.*`, `.npmrc`,
1087
+ `.pypirc`, `.git-credentials`, `.pgpass`, `kubeconfig`, `auth.json`, `*.pem`,
1071
1088
  `*.key` and similar) never go into that ref, because `git push --mirror` sends
1072
- it. When they are changed, untracked or ignored, the CLI copies them to the
1073
- backups folder, readable by you only.
1089
+ it. When they are changed, untracked or ignored, also inside an ignored
1090
+ folder, the CLI copies them to the backups folder, readable by you only.
1074
1091
  - Outside a repository, the backup is a copy of the folder, except
1075
1092
  `node_modules`, `dist`, `build`, `.next`, `venv`, `.venv`, `__pycache__`,
1076
1093
  `.cache` and `.turbo`.
1077
1094
  - A file over 20 MB, or an untracked folder with more than 5,000 files, is left
1078
1095
  out and named in the closing report. The run still starts.
1096
+ - The backup cannot hold a changed submodule, a nested repository, a symlink, or
1097
+ a staged version of a file that the working tree no longer has. The start line
1098
+ counts them, and the closing report names each one with its reason. An ignored
1099
+ folder that takes too long to search for credential files is named the same
1100
+ way.
1079
1101
  - A run that starts in a folder holding several projects takes its backup when
1080
1102
  it moves to the one you choose with `onboard start --move`.
1103
+ - A backup that fails is recorded for the run. When a run has no backup, the
1104
+ closing report says that a restore has nothing to put back.
1105
+ - `onboard credentials` reports the backup as `backup.status`: `ok`, `partial`
1106
+ with each path it left out and why, `pending` when the backup waits for
1107
+ `onboard start --move`, or `failed` with the cause. A symlink to a file or
1108
+ folder the backup holds does not count as left out. The onboarding plan lists
1109
+ a `partial` or `failed` backup under the changes that need your approval, and
1110
+ waits for your answer.
1081
1111
 
1082
1112
  Backups live in `~/.copilotkit/backups/<run-id>/`, or in
1083
1113
  `$COPILOTKIT_CONFIG_DIR/backups/` when that is set. Besides the current run, the
1084
1114
  CLI keeps the newest four ended runs for up to 14 days, and the newest five runs
1085
1115
  that have not ended for up to 90 days, because such a run can still be going on
1086
- in another project. It deletes the git ref with the folder. A run that a start
1116
+ in another project. A run that has not ended is ranked by the last step it was
1117
+ served, so a long run is not deleted by later starts. It deletes the git ref with the folder. A run that a start
1087
1118
  re-enters or `onboard resume` carries on counts as not ended again, and its age
1088
1119
  counts from then.
1089
1120
 
@@ -1099,7 +1130,8 @@ copilotkit onboard restore --run <run-id> --path src/app.ts
1099
1130
  A restore keeps the files the run added. It skips a file you changed after the
1100
1131
  run ended, unless you add `--force`. A run that stopped with no closing report
1101
1132
  has no recorded end, so the CLI cannot tell its edits from yours: a restore then
1102
- puts back deleted files only, and a changed file needs `--force`. It exits 1 when the run has no backup or a
1133
+ puts back deleted files, and files that hold only the version committed at the
1134
+ start, which git keeps. Any other changed file needs `--force`. It exits 1 when the run has no backup or a
1103
1135
  `--path` is not in the backup.
1104
1136
 
1105
1137
  ### Tripwire
@@ -1108,13 +1140,34 @@ Before each step, the CLI checks the project against the backup. It stops the ru
1108
1140
  and shows you what changed when:
1109
1141
 
1110
1142
  - a file you had uncommitted changes in is deleted,
1143
+ - a file you had uncommitted changes in loses lines you added, in whole or in
1144
+ part, and nothing new takes their place: `git checkout -- .`, `git restore .`
1145
+ and `git checkout -p` do this, and so does a revert followed by an edit
1146
+ elsewhere in the file, or a file put back to its staged version,
1111
1147
  - more than 10 files are deleted,
1112
1148
  - HEAD no longer contains the commit the run started on, or
1113
1149
  - a stash entry of this worktree was added or removed.
1114
1150
 
1115
- Edits, new files, env files and dependency files never stop it. A file whose
1116
- content moved to a new path counts as renamed, not deleted. A new branch that
1117
- still contains the start commit does not stop it.
1151
+ Other edits, new files, env files and dependency files never stop it. A file
1152
+ whose content moved to a new path counts as renamed, not deleted. One deleted
1153
+ committed file does not stop it either: git and the backup both hold it, and the
1154
+ closing report lists it with the restore command. A new branch that still
1155
+ contains the start commit does not stop it.
1156
+
1157
+ The revert check ignores trailing whitespace, line endings and blank lines. A
1158
+ formatter that strips them does not stop the run. Leading indentation counts,
1159
+ because it is content in Python, YAML and Makefiles. A line the run rewrites is
1160
+ an edit, not a revert. A line the run moves, sorts or swaps is still in the
1161
+ file, so it does not stop the run. Lines count by occurrence: when you wrote a
1162
+ line twice and the run removes one copy, the run stops. Credential files such
1163
+ as `.npmrc` count too. The check reads only files that changed since the
1164
+ start. A file over 1 MB, or a file that is not text, counts only when it holds
1165
+ the committed version exactly. After `copilotkit onboard tripwire --continue`,
1166
+ a reverted file stays accepted until its content changes. A new modification
1167
+ time alone does not end it.
1168
+
1169
+ A restore from the stop puts back each file as it was at the start. The run's
1170
+ other edits to those files are lost.
1118
1171
 
1119
1172
  Every worktree of a repository shares one stash list, so the tripwire compares
1120
1173
  stash entries by commit. An entry that existed at the start always counts, so
@@ -1149,10 +1202,11 @@ Outside a repository, `copilotkit init` runs `git init` in the new app and makes
1149
1202
  an initial commit when a git identity is configured, so you have a restore point
1150
1203
  before you start editing.
1151
1204
 
1152
- Inside a repository you already have, it does neither. A second `git init` would
1153
- make the new app a nested repository: commits made in it would go to the inner
1154
- repository, while the outer one saw only an untracked directory. The CLI names
1155
- the repository it found and leaves the new app for you to commit. A repository
1205
+ Inside a repository you already have, it does neither. This includes a target
1206
+ folder that is a repository itself. A second `git init` would make the new app a
1207
+ nested repository: commits made in it would go to the inner repository, while the
1208
+ outer one saw only an untracked directory. The CLI names the repository it found,
1209
+ commits nothing, and leaves the new app for you to review with `git status`. A repository
1156
1210
  at your home directory, or above it, does not count here, so an app created below
1157
1211
  it gets its own `git init`.
1158
1212
 
@@ -1283,6 +1337,10 @@ browser. `verify` reads the runtime's own reported license to tell the two
1283
1337
  apart, and only a running runtime can answer that, so the check stays `UNKNOWN`
1284
1338
  when the runtime is unreachable.
1285
1339
 
1340
+ For SSE runtimes, `--round-trip` reports an AG-UI `RUN_ERROR` message before
1341
+ polling for a saved answer. Intelligence JSON responses do not carry these
1342
+ events; inspect runtime and agent logs when that transport reports no answer.
1343
+
1286
1344
  Every check reports `PASS`, `FAIL`, or `UNKNOWN`, and `UNKNOWN` never means the
1287
1345
  check passed — an unreachable Intelligence API leaves the API key unproven
1288
1346
  rather than condemning it. `verify` exits non-zero unless every check passed, so
@@ -1295,6 +1353,12 @@ wired app returns too. The report shows it as `WARN`, `--json` names it in
1295
1353
  warns when the agent answers without the context value, because a correctly
1296
1354
  wired agent that keeps to its own task answers that way too.
1297
1355
 
1356
+ `page_context_reaches_agent` runs after every passing round trip, also for a
1357
+ frontend whose files call no context hook. CopilotKit's frontend sends context
1358
+ entries of its own, such as the A2UI catalog, and an agent that breaks on
1359
+ context fails every browser chat while a plain request still answers. For such a
1360
+ frontend, any answer passes, and a run with no answer fails.
1361
+
1298
1362
  With `--json` the payload is the only thing on stdout and every diagnostic goes
1299
1363
  to stderr, so piping is safe.
1300
1364
 
@@ -1330,7 +1394,10 @@ checks.
1330
1394
  2. `"runtimeUrl"` in `.copilotkit/project.json` — an absolute URL for a
1331
1395
  project whose runtime is somewhere none of the below can find it. Add it by
1332
1396
  hand, or let `project select --runtime-url <url>` or
1333
- `onboard runtime-url --url <url>` write it. The CLI never removes one.
1397
+ `onboard runtime-url --url <url>` write it. The CLI never removes one, but
1398
+ in an onboarding run it can replace one that refuses connections:
1399
+ `verify --round-trip --runtime-url <url>` and `onboard proof-check` can
1400
+ write the new URL. See [`verify` probes port 3000 while the app runs on another port](#verify-probes-port-3000-while-the-app-runs-on-another-port).
1334
1401
  3. `COPILOTKIT_RUNTIME_URL` in the project's `.env` / `.env.local`, when it is
1335
1402
  absolute.
1336
1403
  4. The port the app's own dev configuration declares: `PORT` in its env files,
@@ -1408,10 +1475,33 @@ request in hand is a `resource/request`, and an `info` call never is. A runtime
1408
1475
  below `@copilotkit/runtime` 1.70.2 reports no `singleRoute` block and therefore
1409
1476
  cannot say, so the check is `UNKNOWN` there and names the upgrade.
1410
1477
 
1478
+ ### Sending one run body and reading its events
1479
+
1480
+ `--send-run <file>` sends the AG-UI run body in `<file>` to the agent that
1481
+ `--agent` names, and writes the events the run streams to
1482
+ `<file name>.events.jsonl` beside it. It runs no check. It prints the answer
1483
+ text, the tool calls, and the events path, and exits non-zero when the run did
1484
+ not finish or ended in a `RUN_ERROR`.
1485
+
1486
+ ```bash
1487
+ copilotkit verify --send-run .copilotkit/proof/context-run.json --agent incident_triage --json
1488
+ ```
1489
+
1490
+ A runtime wired to Intelligence answers the run with a join token instead of an
1491
+ event stream, and the events travel over the realtime gateway. The token is
1492
+ single-use and expires 30 seconds after the run starts. The command joins the
1493
+ gateway channel as soon as the run answers. If the gateway still refuses the
1494
+ token, the command asks the runtime's `/connect` route for a fresh one, once,
1495
+ and reads only this run from the channel's replay. Every send gets a new
1496
+ `runId`, and a body without `threadId` gets one. A runtime mounted
1497
+ `mode: "single-route"` gets the run inside its envelope. A second send of the
1498
+ same file replaces its events file. `--timeout` bounds the whole capture
1499
+ (default: 90 seconds).
1500
+
1411
1501
  ### Proving the agent runs, not just that it is configured
1412
1502
 
1413
1503
  Every check above describes the project. `--round-trip` makes it work: it sends
1414
- one real request through the runtime and reads the answer back from the thread.
1504
+ one real request through the runtime and reads the agent's answer.
1415
1505
 
1416
1506
  ```bash
1417
1507
  copilotkit verify --round-trip
@@ -1419,14 +1509,23 @@ copilotkit verify --round-trip --agent incident_triage # several declared
1419
1509
  copilotkit verify --round-trip --header "Cookie: session=…" # auth-gated app
1420
1510
  ```
1421
1511
 
1422
- It reads the answer back from `GET /threads/:id/messages` rather than from the
1423
- run's response, because those responses differ by mode. In Intelligence mode the
1424
- run returns a thread lock and a gateway URL, and the agent's events travel to the
1425
- browser over the realtime gateway — so a 200 there proves a run started, which is
1426
- precisely the outcome a runtime that dies mid-turn also produces. Reading the
1427
- thread is one assertion for both modes, and it proves the stronger fact: the
1428
- answer was recorded, not merely emitted. The thread the run reports wins over the
1429
- one the CLI sent, because Intelligence rewrites both ids when it takes the lock.
1512
+ In Intelligence mode, the run returns a thread lock, a join token and a gateway
1513
+ URL. The agent's events travel over the realtime gateway, on the stream that the
1514
+ app's chat shows. `verify` joins that stream as soon as the run answers, and
1515
+ reads the answer from it. A 200 on the run proves only that a run started. A
1516
+ runtime that stops mid-turn also returns that 200, so the answer itself must
1517
+ arrive. The platform saves the thread from the same events later. Under load,
1518
+ the saved thread can lag the run by minutes, so it does not decide the verdict.
1519
+
1520
+ In four cases, `verify` reads the answer back from `GET /threads/:id/messages`:
1521
+
1522
+ - The runtime streams SSE.
1523
+ - This Node.js has no `WebSocket`.
1524
+ - The gateway refuses the join.
1525
+ - The stream ends with no text.
1526
+
1527
+ The thread that the run reports wins over the thread that the CLI sent, because
1528
+ Intelligence rewrites both ids when it takes the lock.
1430
1529
 
1431
1530
  The assertion is that a non-empty answer came back, never what it said, so the
1432
1531
  verdict does not depend on the model behind the agent. It costs a model call and
@@ -1437,7 +1536,9 @@ is the project's own code and usually reads a signed-in session, which a CLI
1437
1536
  request does not carry, so an auth-gated app refusing it is that app working
1438
1537
  correctly. Pass what it reads with `--header`, repeatable. `verify` sends
1439
1538
  the header on every request to the runtime, `/info` included, so a runtime
1440
- behind auth needs no local proxy.
1539
+ behind auth needs no local proxy. If `/info` answers 401 or 403,
1540
+ `runtime_reachable` names `--header` as the fix, not `--runtime-url`. If the run
1541
+ already sent headers, it names the headers that the runtime refused.
1441
1542
 
1442
1543
  ### Proving a thread the app created
1443
1544
 
@@ -1456,7 +1557,10 @@ no thread. It reads the thread from app-api with the project key, so it needs no
1456
1557
  `--expect-learning-container` checks that same thread. A pass proves that the
1457
1558
  agent's answer was recorded on that thread. It does not prove which end user the
1458
1559
  thread belongs to. A thread app-api does not hold for this project is a `FAIL`.
1459
- Only an answer after the thread's newest user message counts. Inside an
1560
+ Only an answer after the thread's newest user message counts. App-api can save
1561
+ that answer minutes after the run under load. If the newest user message has no
1562
+ answer yet, `--thread` reads the thread again once a second. It waits up to 60
1563
+ seconds before it reports a `FAIL`. Inside an
1460
1564
  onboarding run, a thread that did not change after the run started is a `FAIL`,
1461
1565
  because its answer can predate the app as it is now. With `--agent`, a thread
1462
1566
  of another agent is a `FAIL`, and the evidence names the thread's own agent.
@@ -1475,6 +1579,15 @@ the coding agent, decides three things about it:
1475
1579
  to the run's code. `developer` means an answer or an action only the developer
1476
1580
  can give. Where the check started a server, the step carries the last lines of
1477
1581
  its log.
1582
+ - A failing `runtime-answers` or `round-trip:agent_answers` check names why in
1583
+ `failureKind`, such as `runtime-timeout`, `run-error`, `run-refused`,
1584
+ `read-refused`, `agent-missing` or `agent-ambiguous`. `run-refused` is a run
1585
+ the runtime refused with 401, 402, 403 or 429. That status usually comes from
1586
+ the Intelligence platform key or the app's own auth, so it names no provider.
1587
+ A failed run whose error carried the provider's own code also names it in
1588
+ `providerError`: `auth`, `quota`, `model-not-found`, `rate-limit` or `other`.
1589
+ It is read from that code, never from a status or a message.
1590
+ `verify --round-trip --json` reports both on `roundTrip` too.
1478
1591
  - When the same check fails three proof checks in a row, the command prints
1479
1592
  `Status: stopped`. A later `onboard proof-check` in the same attempt starts no
1480
1593
  server and prints the same stop. Recording the attempt with `onboard proof`
@@ -1571,6 +1684,33 @@ It needs no bound run. The URL must name the mount path: a bare
1571
1684
  `http://localhost:3001` is refused, because `verify` would probe `/`. With no
1572
1685
  project record, it writes nothing and exits non-zero.
1573
1686
 
1687
+ Inside an onboarding run, a `verify --round-trip --runtime-url <url>` that
1688
+ passes on a runtime other than the recorded one does not count for the run.
1689
+ `verify` says so on stderr, and in `roundTripNotRecorded` with `--json`, and
1690
+ names this command.
1691
+
1692
+ There is one exception. The pass counts, and `verify` writes `<url>` into the
1693
+ record, when all of these are true:
1694
+
1695
+ - the recorded URL refuses the connection. A timeout, a TLS error, or any
1696
+ answer, even an error, keeps the record;
1697
+ - `<url>` is on this machine;
1698
+ - a process whose working directory is inside this project listens on the
1699
+ port of `<url>`.
1700
+
1701
+ `verify` asks the recorded URL without the `--header` values. In the same
1702
+ run, `onboard proof-check` replaces a recorded URL where nothing answers when
1703
+ the app's server was already running. It writes the port that server holds. `onboard proof` then names that runtime too. The CLI reads
1704
+ `localhost`, `127.0.0.1`, `0.0.0.0`, and `[::1]` on the same port and path as
1705
+ one runtime.
1706
+
1707
+ `onboard proof-check` restarts a server of the app that started before an env file it reads
1708
+ was written, and names the old pids under `servers[].restarted`. After it starts a server, it
1709
+ waits up to 90 seconds for the runtime's `/info`. It waits only while nothing answers or the
1710
+ server answers with an error, as a dev server does while it compiles. A runtime still not up
1711
+ after the wait fails `runtime-answers` with `runtime-not-found`. Any other answer, such as a
1712
+ 401, goes on to `verify`. `serverWaitMs` says how long the wait took.
1713
+
1574
1714
  ### A model key has no credits or is rejected
1575
1715
 
1576
1716
  A key with no credits passes every static check. The first model call then
@@ -1597,18 +1737,92 @@ in the environment instead. A key you export in the shell, or set with direnv or
1597
1737
  the value came from: `env-file` or `environment`.
1598
1738
 
1599
1739
  - `pass`: the vendor served a model call with the key.
1600
- - `fail`: the vendor refused the key. The cause is `model_quota` (no credits) or
1601
- `model_auth` (a rejected key).
1740
+ - `fail`: the vendor refused the key or the app's model. The cause is
1741
+ `model_quota` (no credits), `model_auth` (a rejected key), or
1742
+ `model_unavailable` (the vendor does not serve the app's model to this key).
1602
1743
  - `missing`: neither the env file nor the environment holds a real value for
1603
1744
  the key.
1604
1745
  - `unsupported` or `undetermined`: the check did not settle it. A rate limit, a
1605
1746
  vendor outage, or a probe model the key may not use proves nothing about the
1606
1747
  key, so none of them is a `fail`.
1607
1748
 
1608
- It does not send the key when a base URL such as `OPENAI_BASE_URL` points the
1609
- SDK at another endpoint, or when the shell exports a different value for the
1610
- key. It never prints the key, and it never prints the vendor's error message,
1611
- because a vendor can echo part of the key in it.
1749
+ The probe proves the key, not the app's model. When `COPILOTKIT_AGENT_MODEL` names the
1750
+ app's model as `provider:model` or `provider/model`, for the same vendor as the key, the
1751
+ command also sends a one-token call with that model. For OpenAI, that call goes through
1752
+ the Responses API, which the AI SDK uses. The JSON reports the model as `model`, where
1753
+ it was set as `modelSource`, and the env file that holds it as `modelFile`. The fix for a
1754
+ refused model names that file. The key and the model can live in different files, as in
1755
+ the Microsoft Agent Framework Python starter. A model the vendor says it does not serve is a `fail` with
1756
+ the cause `model_unavailable`. When the probe passed, the message names the model that the
1757
+ app's `.env.example` sets in `COPILOTKIT_AGENT_MODEL`, if it is a different model for the same
1758
+ vendor. It never names the probe model: the probe sends a plain request, and the app sends
1759
+ system messages and page context, so a model that answers the probe can still fail every chat. After the probe passed, a 403 or a spent quota on the app's
1760
+ model is `model_unavailable` too: the key works, and Google gives some models no free-tier
1761
+ quota. A bare 404 is `undetermined`, because a wrong base URL path answers 404 too. The command reads the variable from the shell first, then from the service whose base URL
1762
+ the key goes to, or else from the first service that sets it (see below). The JSON names
1763
+ that file as `modelFile`, and the fix for a refused model names it too.
1764
+
1765
+ A base URL on OpenAI's own hosts, including a regional one such as
1766
+ `eu.api.openai.com`, is still OpenAI: the command sends its usual calls to that host.
1767
+
1768
+ When `OPENAI_BASE_URL` points at an OpenAI-compatible
1769
+ provider, such as OpenRouter, Groq, or a local Ollama, the command asks that
1770
+ endpoint for its model list instead. A Python agent also reads the older
1771
+ `OPENAI_API_BASE`: LlamaIndex reads only that name, and LangChain's `ChatOpenAI` falls back
1772
+ to it. So when the key's env file belongs to a Python agent, the command counts
1773
+ `OPENAI_API_BASE` as the endpoint. A Python agent's env file is one whose directory, or the `agent` directory below it,
1774
+ holds `pyproject.toml`, `requirements.txt`, `setup.py`, `Pipfile` or `uv.lock`. A
1775
+ JavaScript app with `BuiltInAgent` or the AI SDK reads only `OPENAI_BASE_URL`. When only
1776
+ `OPENAI_API_BASE` points at another provider there, the app sends the key to OpenAI. So
1777
+ the command sends it nowhere and reports `undetermined` with the reason `unread-base-url`.
1778
+ The AI SDK adds the route after the whole base URL, so a base URL with a query string
1779
+ makes the app call a URL such as `…/v1?x=1/chat/completions`. The command sends nothing
1780
+ for it and reports `undetermined` with the reason `base-url-query`. The command reads the base URL from each service
1781
+ that loads env files: the app, whose directory holds the key's `.env` or `.env.local`
1782
+ (never the working directory), and, in `onboard credentials`, the directory of each
1783
+ `--copy-to` target, such as an agent service that runs from `agent/`. Each service reads
1784
+ its `.env.local` before its `.env`, as the app loads them, and its base URL and model go
1785
+ together. The key's own file counts too when it is outside the app, and so do the key
1786
+ file and the base URL that `onboard setup-answers` recorded: `--copy-to` copies the base
1787
+ URL along with the key, from the key file or else from the recorded answer. When the run
1788
+ chose an OpenAI-compatible provider, in `onboard classify` or the setup answers, and no
1789
+ base URL is found, the command sends nothing and reports `undetermined` with the reason
1790
+ `compatible-base-url-missing`. A key with another provider's prefix, such as `gsk_` or
1791
+ `sk-or-`, never goes to OpenAI either: with no base URL it is `undetermined` with the
1792
+ reason `key-not-openai`. So a key in `.env.local` is checked against a base URL in `.env`, and a key kept in
1793
+ a file outside the app is checked against the right endpoint. When the shell and the
1794
+ services name different base URLs (the scheme and host compare without regard to case),
1795
+ the command sends nothing and reports `undetermined` with the reason
1796
+ `endpoint-conflict`. The JSON names the vendor `openai-compatible` and the endpoint's
1797
+ host as `endpointHost`. With `COPILOTKIT_AGENT_MODEL` set, the command sends a
1798
+ one-token chat with that model to `{base}/chat/completions` instead, which gives a
1799
+ real `pass` or `fail`. A key that the endpoint calls invalid is a `fail`, including
1800
+ OpenRouter's numeric code 401. A 402 is a `fail` with the cause `model_quota`: OpenRouter
1801
+ answers a key with no credit that way. A 404 whose message names the app's model, as
1802
+ Ollama answers a model it has not pulled, is a `fail` with the cause
1803
+ `model_unavailable`. Any
1804
+ other refusal is `undetermined` with the reason `endpoint-refused-key`, because
1805
+ a gateway can want a header that the app adds itself. An accepted key is
1806
+ `undetermined` with the reason `endpoint-accepted-key`, because a model list
1807
+ does not prove that a model call is paid for. The command does not send the key
1808
+ when an Anthropic or Google base URL points the SDK at another endpoint, when
1809
+ only the shell sets the base URL for a key in the env file, or when the shell
1810
+ exports a different value for the key. It never prints the key,
1811
+ the base URL's path, or the vendor's error message, because a vendor can echo part of
1812
+ the key in it. It refuses a redirect, so the key never reaches a host that the base URL
1813
+ does not name. A redirect is `undetermined` with the reason `base-url-redirect`: set the
1814
+ base URL to the final address.
1815
+
1816
+ A local server, such as Ollama or LM Studio, needs no key. A local server is an
1817
+ `OPENAI_BASE_URL` in an env file on `localhost`, `127.0.0.1` or `::1`. The OpenAI SDKs
1818
+ still refuse an empty key, so the app needs the stand-in value `not-needed`. When the key
1819
+ is empty or a placeholder, it is `missing` with the reason `local-endpoint-no-key`, and
1820
+ nothing is sent. `onboard credentials` then tells the agent to write `not-needed` to the
1821
+ key's own env file. When the key is `not-needed`, the command asks the server without a
1822
+ key. A model list answer is `undetermined` with the reason `keyless-local-endpoint`. With
1823
+ `COPILOTKIT_AGENT_MODEL` set, the one-token chat gives a `pass` or a `fail`. When the
1824
+ server answers 401 or 403, the key is `missing` with the reason `endpoint-refused-key`.
1825
+ For any other base URL, `not-needed` is an ordinary key value.
1612
1826
 
1613
1827
  During an onboarding run, a `pass` also replaces a `missing` or `fail` that the
1614
1828
  credentials step kept for the same key in the same env file. So after the
@@ -1630,6 +1844,143 @@ binds with a key. Otherwise it asks for the project name. With `--create` or
1630
1844
  `--project`, it runs `project select`, retries once when no key was written, and
1631
1845
  checks the record and the key. Then it reads the default Learning Container.
1632
1846
 
1847
+ When the run recorded the developer's project answer from the setup message, the
1848
+ project-name question carries it as `question.recorded`, and the run uses it
1849
+ without asking again. `onboard setup-answers` records that answer:
1850
+
1851
+ ```bash
1852
+ copilotkit onboard setup-answers --create billing-portal --key-file ~/keys/openai.env
1853
+ copilotkit onboard setup-answers
1854
+ ```
1855
+
1856
+ It records every answer from the setup message for the bound run, so a later
1857
+ step reads it even after the coding agent lost its context:
1858
+
1859
+ - `--purpose <text>`, `--framework <name>`, and `--frontend <name>`.
1860
+ `--framework` takes a framework slug or a name from the framework table that
1861
+ `onboard setup-message --options` lists. Another framework's name is recorded as `frameworkName`, with
1862
+ `framework` set to `custom-ag-ui`, the route that builds it. A name close to
1863
+ a table row is refused with that row named. Add `--custom-framework` to
1864
+ record it as given. A framework recorded before any setup message, for a
1865
+ project with no agent of its own, is kept as a default
1866
+ (`frameworkChoice: default`), because research only inferred it. A provider
1867
+ the developer names later can then replace it with one that takes that
1868
+ provider. Add `--framework-choice developer` for a framework the developer
1869
+ named. A framework recorded with `--vendor-choice existing`, or after the
1870
+ message, is the developer's.
1871
+ - `--vendor <openai|anthropic|google|openai-compatible|other>`, with
1872
+ `--vendor-choice <developer|default|existing>`. An OpenAI-compatible provider
1873
+ also needs `--base-url <url>`, an http or https URL with no user, password, or
1874
+ key in its query or path, and `--model-id <id>`.
1875
+ - The project answer: `--create <name>` or `--project <slug-or-id>`.
1876
+ - The key-file answer: `--key-file <path>` or `--key-later`.
1877
+ - On the local route, the Learning model answer (`--learning later`,
1878
+ `--learning guided`, or `--learning-file <path>`), the connection approval
1879
+ (`--connection approved|declined`), and the approval to write to an env file
1880
+ or `.copilotkit/project.json` with uncommitted changes
1881
+ (`--uncommitted-writes approved|declined`).
1882
+ - The env-file answer, when git tracks the env file the key goes into or does
1883
+ not ignore it: `--env-line approved|alternative|declined`.
1884
+ `credentials/finalize-plan` reads it, so the developer is not asked twice.
1885
+
1886
+ A later call replaces only the answers it names. The vendor flags replace the
1887
+ recorded vendor answer as a whole. With no flag, it prints what the run recorded
1888
+ as JSON. It never reads the key from the key file or the model file, but `--key-file`
1889
+ must name an existing file. When the key file sets `OPENAI_BASE_URL`, the JSON shows it as
1890
+ `keyFileBaseUrl`, and `--vendor openai-compatible` takes it in place of `--base-url`. Any other value is refused, and the message does not repeat it.
1891
+ A free-text answer shaped like a key, such as an `sk-`, `gsk_`, or `AIza` key or
1892
+ a long random token, is refused the same way.
1893
+
1894
+ `onboard setup-message` writes the setup message the coding agent shows the
1895
+ developer. The agent first records what the repository already settles with
1896
+ `setup-answers`, then runs it from the target app directory:
1897
+
1898
+ ```bash
1899
+ copilotkit onboard setup-message --target empty --json
1900
+ copilotkit onboard setup-message --target empty --options --json
1901
+ copilotkit onboard setup-message --target empty --options framework --json
1902
+ copilotkit onboard setup-message --target empty --accept-defaults --json
1903
+ ```
1904
+
1905
+ It prints `status`, the `message` to show word for word, the `open` lines, and
1906
+ `next`, what the agent does after it:
1907
+
1908
+ - `ask`: show `message`, wait, and record the reply. The message puts every
1909
+ default on one line that **go** accepts. The model key is the one question
1910
+ **go** never answers: the developer names the file that holds it, or says
1911
+ "later". The message also holds every line that needs the developer's own
1912
+ answer, such as an env file to untrack or files with uncommitted changes.
1913
+ - `settled`: every line is answered. The run goes on to `credentials/plan`.
1914
+ - `needs-credentials`: an existing app on the managed route has no project
1915
+ finding yet. The command runs the read-only `onboard credentials` check
1916
+ itself first, so the env-file and project lines go into the one message with
1917
+ the key. Only a check that settles neither line leaves this status, and the
1918
+ agent then runs `onboard credentials --json` itself.
1919
+ - `stopped`: that check stopped onboarding. It already filed the stop report,
1920
+ and `stopReason` says why.
1921
+ - `needs-toolchain`: the developer chose a framework this machine cannot run
1922
+ yet. The message names what to install, and the run resumes after a restart.
1923
+
1924
+ The summary line names every line, the recorded ones too, while one of them
1925
+ still holds a default. `--options` shows every line with its recommendation
1926
+ first and its likeliest two or three alternatives. `--options <line>`, such as
1927
+ `--options framework` or `--options frontend`, lists every choice on that one
1928
+ line. `--accept-defaults`
1929
+ records the defaults the reply did not change, then prints what is still open.
1930
+ `--language <typescript|python|dotnet>` picks the framework for a project with
1931
+ no agent, and `--vendor` names a model vendor the developer asked for. A vendor
1932
+ the framework does not take becomes a line of its own. On the local route,
1933
+ which `onboard deployment` now records, the message holds the Learning model,
1934
+ the agreement and the connection lines instead of a project.
1935
+
1936
+ Only the developer accepts the local evaluation agreement, in their own
1937
+ terminal, with `copilotkit local accept-terms`. The command refuses to run
1938
+ without a terminal or when a coding agent runs it. It shows the agreement, its
1939
+ version, the organization, and the signed-in email, and stores the acceptance in
1940
+ `local/eula-acceptance.json` in the CLI configuration directory (mode 600).
1941
+ New local setup and `init --local` use a stored acceptance while it matches the
1942
+ current agreement, organization, and user. Renewal asks every time: under a
1943
+ coding agent, the developer runs `local renew` in their own terminal. A coding
1944
+ agent cannot pass `--accept-eula-version`; scripts still can.
1945
+
1946
+ `onboard local-terms --json` reads the agreement and prints its URL, version,
1947
+ organization, and `accepted`. It creates nothing and requests no license. On the
1948
+ local route, the setup message says the developer accepts the agreement in their
1949
+ own terminal, and `starter/clone` and `deployment/local-evaluation` stop before
1950
+ the install until `accepted` is true.
1951
+
1952
+ When `init --local --install` stops after it cloned the starter, it still
1953
+ installs the starter's dependencies, and its error says so or names the install
1954
+ command.
1955
+
1956
+ #### Model vendors in this release
1957
+
1958
+ Onboarding offers a new agent only the vendors in this table. When onboarding
1959
+ chooses the vendor for a new agent, `onboard setup-answers` refuses another
1960
+ vendor for the framework, and `onboard credentials` and `onboard model-key`
1961
+ refuse another vendor's key before they read or send it. The message names the
1962
+ vendors the framework takes, and never a key value. Each refusal sends the
1963
+ `cli.onboarding.vendor_held_back` event with the framework and the vendor.
1964
+
1965
+ An existing agent keeps its own vendor and model. A vendor recorded with
1966
+ `--vendor-choice existing`, or a run that `onboard classify` placed on an
1967
+ existing agent, is never refused.
1968
+
1969
+ | Framework | Vendors |
1970
+ | -------------------------------------- | -------------------------------------------- |
1971
+ | Built-in CopilotKit agent | OpenAI, OpenAI-compatible, Anthropic, Google |
1972
+ | ADK | Google, OpenAI, OpenAI-compatible |
1973
+ | Claude Agent SDK (Python, TypeScript) | Anthropic |
1974
+ | Every other framework and Custom agent | OpenAI, OpenAI-compatible |
1975
+
1976
+ Anthropic and Google come to the other frameworks in a later release. Their
1977
+ CopilotKit middleware sends the page context as a second system message, after
1978
+ the user message. Anthropic and Google refuse that message order, so every chat
1979
+ fails. The built-in agent sends the context in one leading system message, and
1980
+ ADK puts it in its one system instruction. To use Anthropic or Google for a new
1981
+ agent now, choose the built-in CopilotKit agent. An existing agent on Anthropic
1982
+ or Google can see page context fail until a CopilotKit SDK release fixes it.
1983
+
1633
1984
  Read `status`:
1634
1985
 
1635
1986
  - `ready`: the project, key, and container are settled.
@@ -1738,6 +2089,26 @@ explicitly re-enabled. `copilotkit telemetry reset` restores the full
1738
2089
  fresh-install state: the decision is forgotten and the one-time notice shows
1739
2090
  again on the next interactive run.
1740
2091
 
2092
+ Every event carries `invocation_via`, which tells where the call came from. The
2093
+ CopilotKit skills append a hidden `--via` flag to each command they give, for
2094
+ example `--via skill:copilotkit-cli`. The CLI removes the flag before the
2095
+ command reads its arguments, so the flag never changes what the command does.
2096
+ The values are:
2097
+
2098
+ - `skill:copilotkit`, `skill:copilotkit-cli` or `skill:copilotkit-channels`:
2099
+ the caller passed that tag.
2100
+ - `other`: the caller passed `--via` with a value that is not on that list. The
2101
+ command still runs.
2102
+ - `onboarding`: an untagged call inside an onboarding run, or any `onboard`
2103
+ command. A tag wins over a run, because `onboarding_run_id` already records
2104
+ the run.
2105
+ - `direct`: any other call.
2106
+
2107
+ `cli.command.invoked` also carries `detected_coding_agent` and
2108
+ `detected_coding_agent_source`, read the same way as for onboarding. The CLI
2109
+ reads them once for each command. On Windows it does not read the parent
2110
+ processes for this event, because the PowerShell call can take three seconds.
2111
+
1741
2112
  ## Preview and release builds
1742
2113
 
1743
2114
  Tester-facing prerelease builds are produced by CI via `workflow_dispatch` on
@@ -1917,6 +2288,10 @@ when the flag is off. A candidate file overrides release selection. The CLI down
1917
2288
  its private Helm tool, checks chart support, and pins the chart checksum and runtime
1918
2289
  image digests. Saved stacks resume with their saved release.
1919
2290
 
2291
+ The private chart overlay gives app-api the browser realtime address
2292
+ `ws://localhost:<selected-gateway-port>/client`. Trajectory live views use this
2293
+ address, including when setup selects a different port for a second local stack.
2294
+
1920
2295
  The September 28 check found that release 0.13.8 lacks the local evaluation profile.
1921
2296
  Automatic setup reports `release_unavailable` before license issuance or cluster creation for this release.
1922
2297
  This is a release packaging blocker, not a request for user configuration.
@@ -1932,10 +2307,10 @@ or prove fresh-install acceptance.
1932
2307
  Use `--candidate /path/to/candidate.json` only to override release selection during
1933
2308
  development or release testing. Full fresh-install acceptance remains incomplete.
1934
2309
 
1935
- Use Docker with at least 4 CPUs, 12 GiB of memory available to containers, and
2310
+ Use Docker with at least 4 CPUs, 4 GiB of memory available to containers, and
1936
2311
  40 GiB free storage for each stack. The CLI measures Docker resources after existing
1937
2312
  workloads. Docker keeps part of its memory limit for itself, so set the limit to
1938
- 14 GiB or more. If the check fails, the message shows the total and available memory
2313
+ 6 GiB or more. If the check fails, the message shows the total and available memory
1939
2314
  and how much to add.
1940
2315
  The CLI downloads private, checksum-verified Helm and k3d tools.
1941
2316
 
@@ -1956,8 +2331,11 @@ browser. Review it, type `accept` exactly, and press Enter. The link stays visib
1956
2331
  if the browser cannot open. Opening the page does not accept; there is no scroll requirement.
1957
2332
  Esc/Ctrl-C/Ctrl-D cancels. The published agreement is usable once Ops enforcement is enabled.
1958
2333
  Template acceptance uses the normal license request and audit write, marked `status: template`.
1959
- Scripts must supply `--accept-eula-version <version>` to `local setup` or `local renew`.
1960
- `local start` also accepts this option when it performs first-time setup.
2334
+ Scripts must supply `--accept-eula-version <version>` to `local setup` or `local renew`,
2335
+ or, for setup, use an acceptance stored by `copilotkit local accept-terms`. `local start` also accepts
2336
+ this option when it performs first-time setup. When a coding agent runs the command, the
2337
+ option is refused and no license is requested: the developer runs `local accept-terms` in
2338
+ their own terminal.
1961
2339
  Generic confirmation does not accept terms. Declining requests no license and preserves saved data.
1962
2340
 
1963
2341
  Local `init` (including `--existing`) uses the same EULA review as `local setup`.