@ia-ccun/code-agent-cli 0.0.52 → 0.0.53-beta.2

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 (89) hide show
  1. package/bin/cli.js +97 -69
  2. package/config/agent/bin/README.md +102 -0
  3. package/config/agent/extensions/aicode-advisor.ts +197 -61
  4. package/config/agent/extensions/aicode-banner.ts +101 -0
  5. package/config/agent/extensions/aicode-btw.ts +677 -183
  6. package/config/agent/extensions/aicode-cd.ts +1017 -0
  7. package/config/agent/extensions/aicode-grillMe.ts +198 -0
  8. package/config/agent/extensions/aicode-pets.ts +351 -0
  9. package/config/agent/extensions/aicode-plan.ts +2 -0
  10. package/config/agent/extensions/aicode-safety-guard.ts +555 -0
  11. package/config/agent/extensions/aicode-tips.ts +69 -30
  12. package/config/agent/extensions/aicode-todo-progress.ts +547 -0
  13. package/config/agent/extensions/context-monitor.ts +30 -15
  14. package/config/agent/extensions/context.ts +132 -60
  15. package/config/agent/extensions/custom-footer.ts +0 -5
  16. package/config/agent/extensions/custom.ts +119 -109
  17. package/config/agent/extensions/error-monitor.ts +38 -51
  18. package/config/agent/extensions/goal.ts +8 -6
  19. package/config/agent/extensions/msg-debug.ts +103 -112
  20. package/config/agent/extensions/ponytail.ts +441 -0
  21. package/config/agent/extensions/review.ts +365 -164
  22. package/config/agent/extensions/tps.ts +87 -0
  23. package/config/agent/extensions/working-msg.ts +164 -51
  24. package/config/agent/help.md +0 -7
  25. package/config/agent/models.json +7 -7
  26. package/config/agent/settings.json +2 -1
  27. package/config/agent/skills/chroma/LICENSE +21 -0
  28. package/config/agent/skills/chroma/chroma-local/SKILL.md +165 -0
  29. package/config/agent/skills/chroma/chroma-local/cli.md +48 -0
  30. package/config/agent/skills/chroma/chroma-local/data-model.md +103 -0
  31. package/config/agent/skills/chroma/chroma-local/error-handling/python.md +166 -0
  32. package/config/agent/skills/chroma/chroma-local/error-handling/typescript.md +231 -0
  33. package/config/agent/skills/chroma/chroma-local/local-chroma/python.md +95 -0
  34. package/config/agent/skills/chroma/chroma-local/local-chroma/typescript.md +101 -0
  35. package/config/agent/skills/chroma/chroma-local/metadata/python.md +154 -0
  36. package/config/agent/skills/chroma/chroma-local/metadata/typescript.md +153 -0
  37. package/config/agent/skills/chroma/chroma-local/querying/python.md +147 -0
  38. package/config/agent/skills/chroma/chroma-local/querying/typescript.md +157 -0
  39. package/config/agent/skills/chroma/chroma-local/regex/python.md +69 -0
  40. package/config/agent/skills/chroma/chroma-local/regex/typescript.md +71 -0
  41. package/config/agent/skills/chroma/chroma-local/understanding-a-codebase.md +80 -0
  42. package/config/agent/skills/chroma/chroma-local/updating-deleting/python.md +159 -0
  43. package/config/agent/skills/chroma/chroma-local/updating-deleting/typescript.md +228 -0
  44. package/config/agent/skills/milvus-skill/LICENSE +202 -0
  45. package/config/agent/skills/milvus-skill/README.md +37 -0
  46. package/config/agent/skills/milvus-skill/SKILL.md +259 -0
  47. package/config/agent/skills/milvus-skill/references/collection.md +86 -0
  48. package/config/agent/skills/milvus-skill/references/database.md +24 -0
  49. package/config/agent/skills/milvus-skill/references/index.md +69 -0
  50. package/config/agent/skills/milvus-skill/references/partition.md +29 -0
  51. package/config/agent/skills/milvus-skill/references/patterns.md +150 -0
  52. package/config/agent/skills/milvus-skill/references/user-role.md +90 -0
  53. package/config/agent/skills/milvus-skill/references/vector.md +247 -0
  54. package/config/agent/skills/ponytail/SKILL.md +100 -0
  55. package/config/agent/skills/ponytail-audit/SKILL.md +40 -0
  56. package/config/agent/skills/ponytail-debt/SKILL.md +44 -0
  57. package/config/agent/skills/ponytail-help/SKILL.md +68 -0
  58. package/config/agent/skills/ponytail-review/SKILL.md +56 -0
  59. package/config/agent/skills/zread/README.md +115 -0
  60. package/config/agent/skills/zread/SKILL.md +103 -0
  61. package/config/agent/skills/zread/references/stdio-protocol.md +312 -0
  62. package/dist/banner.d.ts.map +1 -1
  63. package/dist/banner.js +8 -1
  64. package/dist/banner.js.map +1 -1
  65. package/dist/config-loader.d.ts.map +1 -1
  66. package/dist/config-loader.js +9 -2
  67. package/dist/config-loader.js.map +1 -1
  68. package/package.json +7 -7
  69. package/scripts/postinstall.js +58 -1
  70. package/scripts/regression/README.md +224 -0
  71. package/scripts/regression/cases/01-version-and-deps.sh +94 -0
  72. package/scripts/regression/cases/02-extension-loading.sh +130 -0
  73. package/scripts/regression/cases/03-rpc-protocol.sh +259 -0
  74. package/scripts/regression/cases/04-prompt-stream.sh +130 -0
  75. package/scripts/regression/cases/05-slash-commands-and-skills.sh +119 -0
  76. package/scripts/regression/cases/06-tool-execution.sh +115 -0
  77. package/scripts/regression/cases/07-pi-new-features.sh +141 -0
  78. package/scripts/regression/lib/common.sh +287 -0
  79. package/scripts/regression/results/.last_pid +1 -0
  80. package/scripts/regression/results/.last_workdir +1 -0
  81. package/scripts/regression/results/02-extension-loading.log +18 -0
  82. package/scripts/regression/results/03-prompt-stream.log +16 -0
  83. package/scripts/regression/results/03-rpc-protocol.log +27 -0
  84. package/scripts/regression/results/04-slash-commands-and-skills.log +11 -0
  85. package/scripts/regression/results/05-tool-execution.log +8 -0
  86. package/scripts/regression/results/06-pi-new-features.log +29 -0
  87. package/scripts/regression/run-all.sh +187 -0
  88. package/config/agent/dangerous-patterns.json +0 -106
  89. package/config/agent/extensions/bash-check.ts +0 -227
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @author: xujianjiang
3
+ * Token 性能统计扩展
4
+ *
5
+ * 功能说明:
6
+ * - 在每轮对话结束时显示 Token 使用统计
7
+ * - 显示处理速度(token/秒)
8
+ * - 显示输入输出 Token 数量
9
+ * - 显示耗时(智能格式化:ms/秒/分+秒)
10
+ *
11
+ * 输出格式示例:
12
+ * 2026-06-08T16:19:54 | ✨ 处理完成 | 15.2 token/秒 | ↓out 1,234 | ↑in 567 | 11.2秒
13
+ *
14
+ * 放置位置:config/agent/extensions/
15
+ */
16
+ import type { AssistantMessage } from "@earendil-works/pi-ai";
17
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
18
+
19
+ function isAssistantMessage(message: unknown): message is AssistantMessage {
20
+ if (!message || typeof message !== "object") return false;
21
+ const role = (message as { role?: unknown }).role;
22
+ return role === "assistant";
23
+ }
24
+
25
+ function formatDateTime(date: Date): string {
26
+ const year = date.getFullYear();
27
+ const month = String(date.getMonth() + 1).padStart(2, "0");
28
+ const day = String(date.getDate()).padStart(2, "0");
29
+ const hour = String(date.getHours()).padStart(2, "0");
30
+ const minute = String(date.getMinutes()).padStart(2, "0");
31
+ const second = String(date.getSeconds()).padStart(2, "0");
32
+ return `${year}-${month}-${day}T${hour}:${minute}:${second}`;
33
+ }
34
+
35
+ function formatDuration(ms: number): string {
36
+ if (ms < 1000) {
37
+ return `${ms}ms`;
38
+ } else if (ms < 60000) {
39
+ return `${(ms / 1000).toFixed(1)}秒`;
40
+ } else {
41
+ const mins = Math.floor(ms / 60000);
42
+ const secs = Math.floor((ms % 60000) / 1000);
43
+ return `${mins}分${secs}秒`;
44
+ }
45
+ }
46
+
47
+ export default function (pi: ExtensionAPI) {
48
+ let agentStartMs: number | null = null;
49
+
50
+ pi.on("agent_start", () => {
51
+ agentStartMs = Date.now();
52
+ });
53
+
54
+ pi.on("agent_end", (event, ctx) => {
55
+ if (!ctx.hasUI) return;
56
+ if (agentStartMs === null) return;
57
+
58
+ const elapsedMs = Date.now() - agentStartMs;
59
+ agentStartMs = null;
60
+ if (elapsedMs <= 0) return;
61
+
62
+ let input = 0;
63
+ let output = 0;
64
+ let cacheRead = 0;
65
+ let cacheWrite = 0;
66
+ let totalTokens = 0;
67
+
68
+ for (const message of event.messages) {
69
+ if (!isAssistantMessage(message)) continue;
70
+ input += message.usage.input || 0;
71
+ output += message.usage.output || 0;
72
+ cacheRead += message.usage.cacheRead || 0;
73
+ cacheWrite += message.usage.cacheWrite || 0;
74
+ totalTokens += message.usage.totalTokens || 0;
75
+ }
76
+
77
+ if (output <= 0) return;
78
+
79
+ const elapsedSeconds = elapsedMs / 1000;
80
+ const tokensPerSecond = output / elapsedSeconds;
81
+ const now = new Date();
82
+ const timeStr = formatDateTime(now);
83
+ const durationStr = formatDuration(elapsedMs);
84
+ const message = `${timeStr} | ✨ 处理完成 | ${tokensPerSecond.toFixed(2)} token/秒 | ↑in ${input.toLocaleString()} |↓out ${output.toLocaleString()} | ${durationStr}`;
85
+ ctx.ui.notify(message, "info");
86
+ });
87
+ }
@@ -2,11 +2,15 @@
2
2
  * @author: xujianjiang
3
3
  * working-message
4
4
  *
5
- * 自定义工作消息,格式类似 Claude Code: ✶ xxx… (时间 · tokens)
5
+ * 自定义工作消息,格式类似 Claude Code: ✶ xxx… (时间)
6
+ *
7
+ * 改进:使用 dispose 模式防止内存泄漏
8
+ * - 使用明确类型,避免 any
9
+ * - 实现可靠的定时器清理机制
10
+ * - 双重保障确保资源释放
6
11
  */
7
12
 
8
- import type { ExtensionAPI, TurnEndEvent } from "@earendil-works/pi-coding-agent";
9
- import type { AssistantMessage } from "@earendil-works/pi-ai";
13
+ import type { ExtensionAPI, ExtensionContext, TurnEndEvent } from "@earendil-works/pi-coding-agent";
10
14
 
11
15
  // 主题色 #49bccf
12
16
  const accentColor = "\x1b[38;2;73;188;207m";
@@ -44,10 +48,100 @@ const workingMessages = [
44
48
  "Algorithm", "Architecture", "Database", "Cache", "Queue", "Microservice",
45
49
  ];
46
50
 
47
- let intervalId: ReturnType<typeof setInterval> | null = null;
48
- let startTime = 0;
49
- let totalTokens = 0;
51
+ /**
52
+ * 工作消息状态管理器 - 使用 dispose 模式
53
+ * 确保定时器和 UI 引用的生命周期管理,防止内存泄漏
54
+ */
55
+ class WorkingMessageStateManager {
56
+ // ✅ 使用明确类型,避免 any
57
+ private _ui: ExtensionContext['ui'] | null = null;
58
+ private _intervalId: ReturnType<typeof setInterval> | null = null;
59
+ private _startTime: number = 0;
60
+ private _disposed: boolean = false;
61
+
62
+ // Getter 方法
63
+ get ui(): ExtensionContext['ui'] | null {
64
+ return this._ui;
65
+ }
66
+
67
+ get intervalId(): ReturnType<typeof setInterval> | null {
68
+ return this._intervalId;
69
+ }
70
+
71
+ get startTime(): number {
72
+ return this._startTime;
73
+ }
74
+
75
+ isDisposed(): boolean {
76
+ return this._disposed;
77
+ }
78
+
79
+ // Setter 方法(检查 disposed 状态)
80
+ setUI(ui: ExtensionContext['ui'] | null): void {
81
+ if (this._disposed) {
82
+ console.warn('[working-msg] State already disposed, cannot set UI');
83
+ return;
84
+ }
85
+ this._ui = ui;
86
+ }
87
+
88
+ setInterval(intervalId: ReturnType<typeof setInterval> | null): void {
89
+ if (this._disposed) {
90
+ console.warn('[working-msg] State already disposed, cannot set interval');
91
+ return;
92
+ }
93
+ this._intervalId = intervalId;
94
+ }
95
+
96
+ setStartTime(startTime: number): void {
97
+ if (this._disposed) {
98
+ console.warn('[working-msg] State already disposed, cannot set start time');
99
+ return;
100
+ }
101
+ this._startTime = startTime;
102
+ }
103
+
104
+ /**
105
+ * dispose() - 清理所有资源
106
+ * ✅ 双重保障:清理定时器 + 清理 UI 引用
107
+ * ✅ disposed 标记防止重复清理
108
+ */
109
+ dispose(): void {
110
+ if (this._disposed) {
111
+ return; // 防止重复 dispose
112
+ }
50
113
 
114
+ // ✅ 清理定时器(双重保障)
115
+ if (this._intervalId) {
116
+ clearInterval(this._intervalId);
117
+ this._intervalId = null;
118
+ }
119
+
120
+ // ✅ 清理 UI 引用
121
+ if (this._ui) {
122
+ try {
123
+ this._ui.setWorkingMessage(undefined);
124
+ } catch (error) {
125
+ // ✅ 忽略错误,确保清理继续
126
+ console.warn('[working-msg] Error clearing working message:', error);
127
+ }
128
+ this._ui = null;
129
+ }
130
+
131
+ this._disposed = true;
132
+ }
133
+
134
+ /**
135
+ * reset() - 重置状态(用于新的 turn)
136
+ */
137
+ reset(): void {
138
+ this.dispose(); // 先清理旧资源
139
+ this._disposed = false; // 重置 disposed 标记
140
+ this._startTime = 0;
141
+ }
142
+ }
143
+
144
+ // 工具函数
51
145
  function getNextMessage(): string {
52
146
  const randomIndex = Math.floor(Math.random() * workingMessages.length);
53
147
  return workingMessages[randomIndex];
@@ -60,56 +154,75 @@ function formatTime(seconds: number): string {
60
154
  return `${mins} m ${secs} s`;
61
155
  }
62
156
 
63
- function formatTokens(tokens: number): string {
64
- if (tokens < 1000) return `${tokens}`;
65
- return `${(tokens / 1000).toFixed(1)}k`;
157
+ /**
158
+ * ✅ 改进的定时器逻辑
159
+ * - 不依赖 try-catch
160
+ * - 检查 disposed 状态
161
+ * - 使用 state.ui(明确类型)
162
+ */
163
+ function startInterval(state: WorkingMessageStateManager): void {
164
+ if (state.isDisposed() || !state.ui) {
165
+ return;
166
+ }
167
+
168
+ const intervalId = setInterval(() => {
169
+ // ✅ 每次执行前检查 disposed 和 UI 状态
170
+ if (state.isDisposed() || !state.ui) {
171
+ // ✅ 自动清理
172
+ state.dispose();
173
+ return;
174
+ }
175
+
176
+ // ✅ 安全执行(明确类型)
177
+ const elapsed = Math.floor((Date.now() - state.startTime) / 1000);
178
+ const timeStr = formatTime(elapsed);
179
+ const msg = `${accentColor} ✶ ${getNextMessage()}…${reset} (${timeStr})`;
180
+
181
+ try {
182
+ state.ui.setWorkingMessage(msg);
183
+ } catch (error) {
184
+ // ✅ 如果 UI 调用失败,自动清理
185
+ console.warn('[working-msg] UI call failed, disposing:', error);
186
+ state.dispose();
187
+ }
188
+ }, 3000);
189
+
190
+ state.setInterval(intervalId);
66
191
  }
67
192
 
193
+ /**
194
+ * 扩展主函数 - 使用 dispose 模式管理状态
195
+ */
68
196
  export default function workingMessageExtension(pi: ExtensionAPI) {
69
- // turn_start 时开始循环切换消息
197
+ // ✅ 单一状态管理器
198
+ const state = new WorkingMessageStateManager();
199
+
200
+ // ✅ session_shutdown - 清理所有资源
201
+ pi.on("session_shutdown", async (_event, _ctx) => {
202
+ });
203
+
204
+ // ✅ turn_start - 初始化状态并启动定时器
70
205
  pi.on("turn_start", async (_event, ctx) => {
71
- if (!ctx.ui) return;
72
-
73
- // 记录开始时间
74
- startTime = Date.now();
75
- totalTokens = 0;
76
-
77
- // 立即设置第一条
78
- const updateMessage = () => {
79
- const elapsed = Math.floor((Date.now() - startTime) / 1000);
80
- const timeStr = formatTime(elapsed);
81
- const tokensStr = formatTokens(totalTokens);
82
- // ✶ 和单词显示为主题色
83
- const msg = `${accentColor} ✶ ${getNextMessage()}…${reset} (${timeStr} · ↓ ${tokensStr} tokens)`;
84
- ctx.ui?.setWorkingMessage(msg);
85
- };
86
-
87
- updateMessage();
88
-
89
- // 每3秒更新一次
90
- if (!intervalId) {
91
- intervalId = setInterval(() => {
92
- // 获取当前 tokens 使用量
93
- for (const entry of ctx.sessionManager.getBranch()) {
94
- if (entry.type === "message" && (entry as any).message?.role === "assistant") {
95
- const msg = (entry as any).message as AssistantMessage;
96
- if (msg.usage?.output) {
97
- totalTokens = msg.usage.output;
98
- }
99
- }
100
- }
101
- updateMessage();
102
- }, 3000);
206
+ if (!ctx.ui) {
207
+ return;
103
208
  }
209
+
210
+ // ✅ 重置状态(清理旧资源)
211
+ state.reset();
212
+ state.setUI(ctx.ui); // ✅ 明确类型:ExtensionContext['ui']
213
+ state.setStartTime(Date.now());
214
+
215
+ // 设置第一条消息
216
+ const elapsed = Math.floor((Date.now() - state.startTime) / 1000);
217
+ const timeStr = formatTime(elapsed);
218
+ const msg = `${accentColor} ✶ ${getNextMessage()}…${reset} (${timeStr})`;
219
+ state.ui?.setWorkingMessage(msg);
220
+
221
+ // ✅ 启动定时器
222
+ startInterval(state);
104
223
  });
105
224
 
106
- // turn结束时停止
107
- pi.on("turn_end", async (_event: TurnEndEvent, ctx) => {
108
- if (intervalId) {
109
- clearInterval(intervalId);
110
- intervalId = null;
111
- }
112
- // 恢复默认消息
113
- ctx.ui?.setWorkingMessage(undefined);
225
+ // ✅ turn_end - 清理所有资源
226
+ pi.on("turn_end", async (_event: TurnEndEvent, _ctx) => {
114
227
  });
115
- }
228
+ }
@@ -470,13 +470,6 @@ aicode-cli --verbose
470
470
  | `--theme <name>` | 指定主题 |
471
471
  | `--model <name>` | 指定模型 |
472
472
  | `--clear` | 启动时清理会话 |
473
-
474
- ### 相关资源
475
-
476
- - **项目仓库**: https://github.com/ia-ccun/code-agent-cli
477
- - **npm 包**: https://www.npmjs.com/package/@ia-ccun/code-agent-cli
478
- - **pi-coding-agent**: 底层 Agent 框架
479
-
480
473
  ---
481
474
 
482
475
  *世界那么哒 · AI 实践落地 @2026*
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "providers": {
3
- "local": {
4
- "name": "local",
3
+ "aicode": {
4
+ "name": "aicode llm",
5
5
  "baseUrl": "https://ai-llm.cc.com/v1",
6
6
  "api": "openai-completions",
7
- "apiKey": "你自己的APIKEY",
7
+ "apiKey": "你自己的APIKEY sk-xxxxxxxxxxxxxxxxxx",
8
8
  "headers": {
9
9
  "User-Agent": "${VERSION}"
10
10
  },
11
11
  "models": [
12
12
  {
13
- "id": "GLM-4.7-W8A8",
14
- "name": "GLM4.7",
15
- "contextWindow": 120000,
13
+ "id": "qwen3.6-35b-a3b",
14
+ "name": "qwen3.6",
15
+ "contextWindow": 128000,
16
16
  "maxTokens": 100000,
17
- "reasoning": true,
17
+ "reasoning": false,
18
18
  "input": ["text"],
19
19
  "cost": {
20
20
  "input": 5,
@@ -10,7 +10,8 @@
10
10
  "~/.aicode-cli/agent/extensions/custom-footer.ts",
11
11
  "~/.aicode-cli/agent/extensions/custom.ts",
12
12
  "~/.aicode-cli/agent/extensions/review.ts",
13
- "~/.aicode-cli/agent/extensions/working-msg.ts"
13
+ "~/.aicode-cli/agent/extensions/working-msg.ts",
14
+ "-extensions/aicode-pets.ts"
14
15
  ],
15
16
  "packages":[
16
17
  "npm:pi-subagents@0.17.1",
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chroma
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,165 @@
1
+ ---
2
+ name: chroma-local
3
+ description: Use when the user needs self-hosted or local Chroma for semantic search, including `ChromaClient`, `HttpClient`, or Python `EphemeralClient`, local persistence, Docker or `chroma run`, or OSS Chroma without Chroma Cloud features.
4
+ ---
5
+
6
+ ## Instructions
7
+
8
+ Determine these before writing code. Prefer discovering them from the repo and the user request. Ask only when the choice materially changes the implementation.
9
+
10
+ 1. **Runtime shape**
11
+ - Are they connecting to a running local server, embedding Chroma into tests, or setting up local development from scratch?
12
+ - Decide whether they need `chroma run`, a Docker or service command, `HttpClient` or `ChromaClient`, or Python `EphemeralClient`.
13
+
14
+ 2. **Persistence**
15
+ - Persistent local data: choose an intentional data path.
16
+ - Disposable test data: use defaults or a temp directory.
17
+
18
+ 3. **Embedding model**
19
+ - Reuse the app's existing embedding provider when possible.
20
+ - Otherwise default to `@chroma-core/default-embed` in TypeScript or the standard local default in Python.
21
+ - If the user explicitly wants OpenAI embeddings in TypeScript, install and use `@chroma-core/openai`.
22
+
23
+ 4. **Indexed data shape**
24
+ - Determine what is being indexed, how it should be chunked, and what metadata is needed for filtering and updates.
25
+
26
+ ## Routing
27
+
28
+ - **Existing local server**
29
+ - Confirm host and port before changing client code.
30
+ - Validate the server is reachable before assuming collections are missing.
31
+
32
+ - **Fresh local development**
33
+ - Add a local startup path such as `chroma run` or the repo's existing Docker or service command.
34
+ - Default to `localhost:8000` unless the repo already uses another address.
35
+
36
+ - **Python tests or disposable local workflows**
37
+ - Prefer `EphemeralClient` when persistence is unnecessary.
38
+ - Call out that data is lost when the process exits.
39
+
40
+ - **Persistent local development**
41
+ - Use a stable data path and make persistence explicit in code or config.
42
+ - Do not silently switch between ephemeral and persistent modes.
43
+
44
+ - **Search integration work**
45
+ - Use `getOrCreateCollection()` in TypeScript or `get_or_create_collection()` in Python.
46
+ - Design document IDs and metadata so upserts and deletes are straightforward.
47
+ - Batch writes when syncing large datasets.
48
+
49
+ ## Ask vs proceed
50
+
51
+ **Ask first:**
52
+ - Embedding model choice (cost and quality implications)
53
+ - Whether they need persistent local data
54
+ - How they are starting the local server
55
+ - Multi-tenant data isolation strategy
56
+
57
+ **Proceed with sensible defaults:**
58
+ - Use `getOrCreateCollection()` (TypeScript) / `get_or_create_collection()` (Python)
59
+ - Use cosine similarity (most common)
60
+ - Chunk size under 8KB
61
+ - Store source IDs in metadata for updates/deletes
62
+ - Use a local server on `localhost:8000` unless the repo already configures another address or is using Python `EphemeralClient`
63
+
64
+ ## What to validate
65
+
66
+ - Correct client import (`ChromaClient`, `HttpClient`, or `Client`)
67
+ - Embedding function package is installed (TypeScript)
68
+ - Local server is reachable before assuming collections are missing
69
+ - Local path and persistence mode are intentional
70
+
71
+ ## Implementation notes
72
+
73
+ - Local Chroma is the right default for development, tests, and self-hosted deployments.
74
+ - OSS Chroma does not include Chroma Cloud-only features such as `Schema()` and `Search()`.
75
+ - If the user asks for hybrid dense and sparse retrieval, treat that as a likely Chroma Cloud requirement unless the repo already implements an OSS workaround.
76
+ - For open source Chroma, dense retrieval with a single embedding function is the normal baseline.
77
+
78
+ ## Minimal patterns
79
+
80
+ Start a local Chroma server when the repo needs one:
81
+
82
+ ```bash
83
+ chroma run
84
+ ```
85
+
86
+ Default address: `localhost:8000`.
87
+
88
+ TypeScript local client:
89
+
90
+ ```typescript
91
+ import { ChromaClient } from 'chromadb';
92
+ import { DefaultEmbeddingFunction } from '@chroma-core/default-embed';
93
+
94
+ const client = new ChromaClient();
95
+
96
+ const embeddingFunction = new DefaultEmbeddingFunction();
97
+ const collection = await client.getOrCreateCollection({
98
+ name: 'my_collection',
99
+ embeddingFunction,
100
+ });
101
+
102
+ // Add documents
103
+ await collection.add({
104
+ ids: ['doc1', 'doc2'],
105
+ documents: ['First document text', 'Second document text'],
106
+ });
107
+
108
+ // Query
109
+ const results = await collection.query({
110
+ queryTexts: ['search query'],
111
+ nResults: 5,
112
+ });
113
+ ```
114
+
115
+ Python local client:
116
+
117
+ ```python
118
+ import chromadb
119
+
120
+ client = chromadb.HttpClient(host="localhost", port=8000)
121
+
122
+ collection = client.get_or_create_collection(name="my_collection")
123
+
124
+ # Add documents
125
+ collection.add(
126
+ ids=["doc1", "doc2"] ,
127
+ documents=["First document text", "Second document text"],
128
+ )
129
+
130
+ # Query
131
+ results = collection.query(
132
+ query_texts=["search query"],
133
+ n_results=5,
134
+ )
135
+ ```
136
+
137
+ ## Learn More
138
+
139
+ Fetch Chroma's `llms.txt` only when you need API or product details that are not already in the repo or this skill: https://docs.trychroma.com/llms.txt
140
+
141
+ ## Available Topics
142
+
143
+ ### Typescript
144
+
145
+ - [Chroma Regex Filtering](./regex/typescript.md) - Learn how to use regex filters in Chroma queries
146
+ - [Query and Get](./querying/typescript.md) - Query and Get Data from Chroma Collections
147
+ - [Metadata](./metadata/typescript.md) - Store and query metadata, including filters and array values
148
+ - [Updating and Deleting](./updating-deleting/typescript.md) - Update existing documents and delete data from collections
149
+ - [Error Handling](./error-handling/typescript.md) - Handling errors and failures when working with Chroma
150
+ - [Local Chroma](./local-chroma/typescript.md) - How to run and use local chroma
151
+
152
+ ### Python
153
+
154
+ - [Chroma Regex Filtering](./regex/python.md) - Learn how to use regex filters in Chroma queries
155
+ - [Query and Get](./querying/python.md) - Query and Get Data from Chroma Collections
156
+ - [Metadata](./metadata/python.md) - Store and query metadata, including filters and array values
157
+ - [Updating and Deleting](./updating-deleting/python.md) - Update existing documents and delete data from collections
158
+ - [Error Handling](./error-handling/python.md) - Handling errors and failures when working with Chroma
159
+ - [Local Chroma](./local-chroma/python.md) - How to run and use local chroma
160
+
161
+ ## General
162
+
163
+ - [Data Model](./data-model.md) - An overview of how Chroma stores data
164
+ - [Integrating Chroma into an existing system](./understanding-a-codebase.md) - Guidance for adding Chroma search to an existing application
165
+ - [Chroma CLI](./cli.md) - Starting and managing a local open source Chroma server from the CLI
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: Chroma CLI
3
+ description: Starting and managing a local open source Chroma server from the CLI
4
+ ---
5
+
6
+ ## Chroma CLI
7
+
8
+ The Chroma CLI can also be used for local open source Chroma workflows. This topic focuses on starting and managing a local server, not Chroma Cloud account setup.
9
+
10
+ ### Install
11
+
12
+ ```bash
13
+ pip install chromadb
14
+ ```
15
+
16
+ ### Start a local server
17
+
18
+ Run Chroma locally on the default address:
19
+
20
+ ```bash
21
+ chroma run
22
+ ```
23
+
24
+ This starts a server on `localhost:8000`.
25
+
26
+ ### Choose a persistent data directory
27
+
28
+ Store local data in a specific path instead of the default working directory:
29
+
30
+ ```bash
31
+ chroma run --path ./chroma-data
32
+ ```
33
+
34
+ ### Change the port
35
+
36
+ If another process already uses port `8000`, pick another one:
37
+
38
+ ```bash
39
+ chroma run --port 8001
40
+ ```
41
+
42
+ Update your client code to match the chosen host and port.
43
+
44
+ ### Local workflow tips
45
+
46
+ - Use a dedicated data directory per environment so dev and test data do not mix.
47
+ - In tests, use disposable directories or clear collections between runs.
48
+ - Check that the server is running before debugging client-side collection errors.