chivgent 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -897
- package/README.zh-CN.md +97 -801
- package/dist/agent.d.ts +30 -2
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +255 -36
- package/dist/agent.js.map +1 -1
- package/dist/auth/oauth.d.ts +51 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +444 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/cli-options.d.ts +9 -4
- package/dist/cli-options.d.ts.map +1 -1
- package/dist/cli-options.js +46 -3
- package/dist/cli-options.js.map +1 -1
- package/dist/cli-runtime.d.ts +33 -0
- package/dist/cli-runtime.d.ts.map +1 -0
- package/dist/cli-runtime.js +90 -0
- package/dist/cli-runtime.js.map +1 -0
- package/dist/cli.js +76 -81
- package/dist/cli.js.map +1 -1
- package/dist/context/compaction.d.ts +5 -2
- package/dist/context/compaction.d.ts.map +1 -1
- package/dist/context/compaction.js +58 -32
- package/dist/context/compaction.js.map +1 -1
- package/dist/context/context-manager.d.ts +23 -0
- package/dist/context/context-manager.d.ts.map +1 -1
- package/dist/context/context-manager.js +200 -35
- package/dist/context/context-manager.js.map +1 -1
- package/dist/context/project-instructions.d.ts +17 -0
- package/dist/context/project-instructions.d.ts.map +1 -0
- package/dist/context/project-instructions.js +191 -0
- package/dist/context/project-instructions.js.map +1 -0
- package/dist/evals/baseline.d.ts +41 -0
- package/dist/evals/baseline.d.ts.map +1 -0
- package/dist/evals/baseline.js +121 -0
- package/dist/evals/baseline.js.map +1 -0
- package/dist/evals/cli.js +27 -1
- package/dist/evals/cli.js.map +1 -1
- package/dist/evals/parse-args.d.ts +2 -0
- package/dist/evals/parse-args.d.ts.map +1 -1
- package/dist/evals/parse-args.js +5 -0
- package/dist/evals/parse-args.js.map +1 -1
- package/dist/evals/report.d.ts +2 -0
- package/dist/evals/report.d.ts.map +1 -1
- package/dist/evals/report.js +12 -8
- package/dist/evals/report.js.map +1 -1
- package/dist/evals/runner.d.ts +3 -0
- package/dist/evals/runner.d.ts.map +1 -1
- package/dist/evals/runner.js +5 -1
- package/dist/evals/runner.js.map +1 -1
- package/dist/evals/task.d.ts.map +1 -1
- package/dist/evals/task.js +1 -0
- package/dist/evals/task.js.map +1 -1
- package/dist/evals/tools.d.ts +4 -1
- package/dist/evals/tools.d.ts.map +1 -1
- package/dist/evals/tools.js +13 -4
- package/dist/evals/tools.js.map +1 -1
- package/dist/events.d.ts +12 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/patch/parse.d.ts +26 -0
- package/dist/patch/parse.d.ts.map +1 -0
- package/dist/patch/parse.js +117 -0
- package/dist/patch/parse.js.map +1 -0
- package/dist/permissions.d.ts +35 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +89 -0
- package/dist/permissions.js.map +1 -0
- package/dist/prompts.d.ts +3 -3
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +5 -3
- package/dist/prompts.js.map +1 -1
- package/dist/providers/client.d.ts +1 -1
- package/dist/providers/client.d.ts.map +1 -1
- package/dist/providers/client.js +19 -1
- package/dist/providers/client.js.map +1 -1
- package/dist/providers/definitions.d.ts +2 -0
- package/dist/providers/definitions.d.ts.map +1 -1
- package/dist/providers/definitions.js +3 -1
- package/dist/providers/definitions.js.map +1 -1
- package/dist/providers/interactive.d.ts +4 -0
- package/dist/providers/interactive.d.ts.map +1 -1
- package/dist/providers/interactive.js +86 -2
- package/dist/providers/interactive.js.map +1 -1
- package/dist/providers/oauth-client.d.ts +14 -0
- package/dist/providers/oauth-client.d.ts.map +1 -0
- package/dist/providers/oauth-client.js +52 -0
- package/dist/providers/oauth-client.js.map +1 -0
- package/dist/providers/openai-compatible-chat.d.ts +1 -0
- package/dist/providers/openai-compatible-chat.d.ts.map +1 -1
- package/dist/providers/openai-compatible-chat.js +1 -0
- package/dist/providers/openai-compatible-chat.js.map +1 -1
- package/dist/providers/openai.d.ts +3 -0
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +72 -10
- package/dist/providers/openai.js.map +1 -1
- package/dist/remote/repl.d.ts.map +1 -1
- package/dist/remote/repl.js +9 -0
- package/dist/remote/repl.js.map +1 -1
- package/dist/repl.d.ts +53 -1
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +554 -10
- package/dist/repl.js.map +1 -1
- package/dist/session-store.d.ts +27 -2
- package/dist/session-store.d.ts.map +1 -1
- package/dist/session-store.js +85 -2
- package/dist/session-store.js.map +1 -1
- package/dist/session.d.ts +20 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +141 -13
- package/dist/session.js.map +1 -1
- package/dist/shell/approval.d.ts +15 -0
- package/dist/shell/approval.d.ts.map +1 -0
- package/dist/shell/approval.js +25 -0
- package/dist/shell/approval.js.map +1 -0
- package/dist/shell/docker.d.ts +20 -0
- package/dist/shell/docker.d.ts.map +1 -0
- package/dist/shell/docker.js +97 -0
- package/dist/shell/docker.js.map +1 -0
- package/dist/shell/factory.d.ts +9 -0
- package/dist/shell/factory.d.ts.map +1 -0
- package/dist/shell/factory.js +13 -0
- package/dist/shell/factory.js.map +1 -0
- package/dist/shell/local.d.ts +5 -1
- package/dist/shell/local.d.ts.map +1 -1
- package/dist/shell/local.js +17 -2
- package/dist/shell/local.js.map +1 -1
- package/dist/shell/native.d.ts +15 -0
- package/dist/shell/native.d.ts.map +1 -0
- package/dist/shell/native.js +99 -0
- package/dist/shell/native.js.map +1 -0
- package/dist/shell/types.d.ts +1 -0
- package/dist/shell/types.d.ts.map +1 -1
- package/dist/tools/apply-patch.d.ts +18 -0
- package/dist/tools/apply-patch.d.ts.map +1 -0
- package/dist/tools/apply-patch.js +53 -0
- package/dist/tools/apply-patch.js.map +1 -0
- package/dist/tools/bash.d.ts +23 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +55 -11
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit-file.d.ts.map +1 -1
- package/dist/tools/edit-file.js +1 -1
- package/dist/tools/edit-file.js.map +1 -1
- package/dist/tools/parallel.d.ts +16 -0
- package/dist/tools/parallel.d.ts.map +1 -0
- package/dist/tools/parallel.js +28 -0
- package/dist/tools/parallel.js.map +1 -0
- package/dist/tools/tool.d.ts +7 -0
- package/dist/tools/tool.d.ts.map +1 -1
- package/dist/tools/tool.js +7 -1
- package/dist/tools/tool.js.map +1 -1
- package/dist/tools/update-plan.d.ts +57 -0
- package/dist/tools/update-plan.d.ts.map +1 -0
- package/dist/tools/update-plan.js +99 -0
- package/dist/tools/update-plan.js.map +1 -0
- package/dist/tools/write-file.d.ts.map +1 -1
- package/dist/tools/write-file.js +1 -1
- package/dist/tools/write-file.js.map +1 -1
- package/dist/transcript-hash.d.ts +4 -0
- package/dist/transcript-hash.d.ts.map +1 -0
- package/dist/transcript-hash.js +6 -0
- package/dist/transcript-hash.js.map +1 -0
- package/dist/tui/activity.d.ts +17 -0
- package/dist/tui/activity.d.ts.map +1 -0
- package/dist/tui/activity.js +188 -0
- package/dist/tui/activity.js.map +1 -0
- package/dist/tui/diff.d.ts +14 -0
- package/dist/tui/diff.d.ts.map +1 -0
- package/dist/tui/diff.js +57 -0
- package/dist/tui/diff.js.map +1 -0
- package/dist/tui/editor-input.d.ts +53 -0
- package/dist/tui/editor-input.d.ts.map +1 -0
- package/dist/tui/editor-input.js +353 -0
- package/dist/tui/editor-input.js.map +1 -0
- package/dist/tui/editor.d.ts +72 -0
- package/dist/tui/editor.d.ts.map +1 -0
- package/dist/tui/editor.js +321 -0
- package/dist/tui/editor.js.map +1 -0
- package/dist/tui/git-diff.d.ts +7 -0
- package/dist/tui/git-diff.d.ts.map +1 -0
- package/dist/tui/git-diff.js +48 -0
- package/dist/tui/git-diff.js.map +1 -0
- package/dist/tui/input.d.ts +14 -0
- package/dist/tui/input.d.ts.map +1 -1
- package/dist/tui/input.js +77 -1
- package/dist/tui/input.js.map +1 -1
- package/dist/tui/live.d.ts +10 -0
- package/dist/tui/live.d.ts.map +1 -1
- package/dist/tui/live.js +42 -5
- package/dist/tui/live.js.map +1 -1
- package/dist/tui/markdown.d.ts +7 -0
- package/dist/tui/markdown.d.ts.map +1 -0
- package/dist/tui/markdown.js +55 -0
- package/dist/tui/markdown.js.map +1 -0
- package/dist/tui/menu.js +1 -1
- package/dist/tui/review.d.ts +27 -0
- package/dist/tui/review.d.ts.map +1 -0
- package/dist/tui/review.js +114 -0
- package/dist/tui/review.js.map +1 -0
- package/dist/tui/slash.d.ts +11 -0
- package/dist/tui/slash.d.ts.map +1 -0
- package/dist/tui/slash.js +13 -0
- package/dist/tui/slash.js.map +1 -0
- package/dist/tui/state.d.ts +5 -0
- package/dist/tui/state.d.ts.map +1 -1
- package/dist/tui/state.js +10 -1
- package/dist/tui/state.js.map +1 -1
- package/dist/tui/syntax.d.ts +6 -0
- package/dist/tui/syntax.d.ts.map +1 -0
- package/dist/tui/syntax.js +48 -0
- package/dist/tui/syntax.js.map +1 -0
- package/dist/tui/view.d.ts +1 -1
- package/dist/tui/view.d.ts.map +1 -1
- package/dist/tui/view.js +21 -9
- package/dist/tui/view.js.map +1 -1
- package/dist/tui/welcome.d.ts +5 -0
- package/dist/tui/welcome.d.ts.map +1 -1
- package/dist/tui/welcome.js +35 -20
- package/dist/tui/welcome.js.map +1 -1
- package/dist/workspace/patch.d.ts +11 -0
- package/dist/workspace/patch.d.ts.map +1 -0
- package/dist/workspace/patch.js +124 -0
- package/dist/workspace/patch.js.map +1 -0
- package/dist/workspace/paths.d.ts.map +1 -1
- package/dist/workspace/paths.js +4 -0
- package/dist/workspace/paths.js.map +1 -1
- package/dist/workspace/types.d.ts +9 -2
- package/dist/workspace/types.d.ts.map +1 -1
- package/dist/workspace/types.js.map +1 -1
- package/dist/workspace.d.ts +4 -3
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +7 -2
- package/dist/workspace.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,960 +1,160 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/chivgent-leaf-mark.png" width="88" alt="">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
> A readable terminal coding agent with a streaming TUI and configurable AI providers.
|
|
6
|
-
|
|
7
|
-

|
|
8
|
-

|
|
9
|
-
[](https://github.com/chivopic/chivgent/actions/workflows/ci.yml)
|
|
10
|
-
[](LICENSE)
|
|
11
|
-

|
|
12
|
-
|
|
13
|
-
`chivgent` connects a Provider-independent agent loop to LLM APIs, tools, and a
|
|
14
|
-
workspace boundary. It can discover files, search source text, read bounded
|
|
15
|
-
file ranges, and optionally edit files or run commands. It works with OpenAI,
|
|
16
|
-
DeepSeek, and compatible Chat Completions endpoints.
|
|
17
|
-
|
|
18
|
-
The project is intentionally compact: it is designed to make the mechanics of
|
|
19
|
-
tool calling, conversation state, Provider adapters, and loop termination easy
|
|
20
|
-
to study before adding production-harness complexity.
|
|
21
|
-
|
|
22
|
-
## Features
|
|
23
|
-
|
|
24
|
-
- A real multi-turn agent loop: model -> tool call -> tool result -> model.
|
|
25
|
-
- Provider-independent runtime messages and tool contracts.
|
|
26
|
-
- A Provider registry: adding a Provider is a declaration, not a CLI change.
|
|
27
|
-
- API keys resolved from `--api-key`, the environment, then an optional file.
|
|
28
|
-
- OpenAI support through the Responses API.
|
|
29
|
-
- DeepSeek support through a reusable OpenAI-compatible Chat Completions client.
|
|
30
|
-
- Custom OpenAI-compatible endpoints through the TUI, CLI options, or environment.
|
|
31
|
-
- A rolling TUI with inline slash-command suggestions and a Provider picker.
|
|
32
|
-
- An interactive session with slash commands, or a single-shot question.
|
|
33
|
-
- Sessions that persist as JSON lines and can be resumed in a later process.
|
|
34
|
-
- A context manager that summarises old turns to stay inside the window.
|
|
35
|
-
- A `--json` event stream for scripting and other front ends.
|
|
36
|
-
- Streamed answers rendered from a typed runtime event stream.
|
|
37
|
-
- Interruptible runs: Ctrl+C stops the current answer; at an idle prompt it exits.
|
|
38
|
-
- Per-attempt Provider timeouts and bounded exponential-backoff retries.
|
|
39
|
-
- Deterministic project discovery through `list_files` and literal `search_text`.
|
|
40
|
-
- Ranged `read_file` output with continuation hints and bounded tool results.
|
|
41
|
-
- Read-only by default; `--allow-writes` adds `write_file` and `edit_file`.
|
|
42
|
-
- An opt-in `bash` tool behind `--allow-shell`, with streamed output.
|
|
43
|
-
- Token usage from the Provider, per turn, per run, per eval task.
|
|
44
|
-
- An eval suite that measures whether the agent completes tasks, not just runs.
|
|
45
|
-
- Remote sessions: one process holds a session, others attach over a local socket.
|
|
46
|
-
- Several clients can watch one session; any of them can interrupt the run.
|
|
47
|
-
- Extensions that add tools, slash commands, event handlers and prompt text.
|
|
48
|
-
- Project extensions gated by a per-directory trust decision, taken before any
|
|
49
|
-
module is imported and refused outright when there is no terminal to ask.
|
|
50
|
-
- Commands run in their own process group, so cancelling kills the whole tree.
|
|
51
|
-
- Command output is truncated from the tail; the full text goes to a temp file.
|
|
52
|
-
- Exact-match `edit_file` that refuses missing or ambiguous edits.
|
|
53
|
-
- Edits preserve the file's own byte order mark and CRLF line endings.
|
|
54
|
-
- Atomic writes: a crash mid-write leaves the original file intact.
|
|
55
|
-
- Safe workspace access with traversal and symlink-escape protection.
|
|
56
|
-
- Root `.gitignore`, generated-directory, and sensitive-path filtering.
|
|
57
|
-
- Tool argument validation, explicit tool errors, and a bounded turn limit.
|
|
58
|
-
- A packaged Node.js CLI with no framework dependency.
|
|
59
|
-
- Unit tests that do not spend API credits.
|
|
60
|
-
|
|
61
|
-
## Quick start
|
|
62
|
-
|
|
63
|
-
### Requirements
|
|
64
|
-
|
|
65
|
-
- Node.js 22 or newer
|
|
66
|
-
- npm
|
|
67
|
-
- An API key for OpenAI, DeepSeek, or a compatible Provider
|
|
68
|
-
|
|
69
|
-
### Install from npm
|
|
5
|
+
<div align="center">
|
|
70
6
|
|
|
71
|
-
|
|
72
|
-
npm install -g chivgent
|
|
73
|
-
chivgent --version
|
|
74
|
-
```
|
|
7
|
+
# chivgent
|
|
75
8
|
|
|
76
|
-
|
|
9
|
+
### A coding agent in your terminal.
|
|
77
10
|
|
|
78
|
-
|
|
79
|
-
chivgent update --check # Check without installing
|
|
80
|
-
chivgent update # Install the newer version, then restart chivgent
|
|
81
|
-
```
|
|
11
|
+
The same category as Claude Code and Codex. You bring the model.
|
|
82
12
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
13
|
+
[](https://www.npmjs.com/package/chivgent)
|
|
14
|
+
[](https://github.com/chivopic/chivgent/actions/workflows/ci.yml)
|
|
15
|
+

|
|
16
|
+
[](LICENSE)
|
|
87
17
|
|
|
88
|
-
|
|
18
|
+
[Architecture](docs/architecture.md) · [Shell](docs/shell-sandbox.md) · [Sign in](docs/subscription-oauth.md) · **English** · [简体中文](README.zh-CN.md)
|
|
89
19
|
|
|
90
|
-
|
|
91
|
-
git clone https://github.com/chivopic/chivgent.git
|
|
92
|
-
cd chivgent
|
|
93
|
-
npm install
|
|
94
|
-
npm run build
|
|
95
|
-
npm install -g .
|
|
96
|
-
```
|
|
20
|
+
</div>
|
|
97
21
|
|
|
98
|
-
|
|
22
|
+
chivgent is a local agent for the directory you have open. The category is the one [Claude Code](https://code.claude.com) and [Codex](https://github.com/openai/codex) occupy: read the project, change it, run it, and come back to the session. The model is yours. An API key, or a ChatGPT or xAI subscription.
|
|
99
23
|
|
|
100
|
-
|
|
24
|
+
The default that category expects is auto mode. Ordinary reads, workspace edits, and sandboxed commands proceed. The agent stops when an action leaves the workspace, or when a command needs the host. Here that policy is `workspace`. It is not a second model reviewing each action, and it is not a bypass. This build does not start there. A session still opens read-only. Pass `--permission-mode workspace`, or the older flags.
|
|
101
25
|
|
|
102
|
-
|
|
26
|
+
## Getting started
|
|
103
27
|
|
|
104
|
-
|
|
105
|
-
export OPENAI_API_KEY="your-api-key"
|
|
106
|
-
chivgent "What does src/agent.ts do?"
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
With DeepSeek:
|
|
28
|
+
You need Node.js 22 or newer.
|
|
110
29
|
|
|
111
30
|
```bash
|
|
112
|
-
|
|
113
|
-
chivgent --provider deepseek "Explain the architecture in src/"
|
|
31
|
+
npm install -g chivgent
|
|
114
32
|
```
|
|
115
33
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
export OPENAI_API_KEY="your-provider-api-key"
|
|
120
|
-
export OPENAI_BASE_URL="https://api.vendor.example/v1"
|
|
121
|
-
export OPENAI_MODEL="vendor-model"
|
|
122
|
-
|
|
123
|
-
chivgent --provider openai-compatible "Explain the architecture in src/"
|
|
124
|
-
```
|
|
34
|
+
Already installed? `chivgent update --check`, then `chivgent update`.
|
|
125
35
|
|
|
126
|
-
Start
|
|
36
|
+
Start it in the project.
|
|
127
37
|
|
|
128
38
|
```bash
|
|
39
|
+
cd /path/to/project
|
|
129
40
|
chivgent
|
|
130
|
-
› What does src/agent.ts do?
|
|
131
|
-
› Where is that loop tested?
|
|
132
|
-
› /exit
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
The conversation is kept across prompts, so follow-up questions do not repeat
|
|
136
|
-
the earlier context. Resume it later with `chivgent --continue` (or
|
|
137
|
-
`chivgent --resume <id>`; `chivgent --sessions` lists what is recorded).
|
|
138
|
-
|
|
139
|
-
Answers stream to stdout as the model produces them, so stdout stays pipeable.
|
|
140
|
-
Tool activity, retries, and run status go to stderr; Provider failures produce a
|
|
141
|
-
non-zero exit code. Use `--no-stream` for one final write, and `--quiet` to hide
|
|
142
|
-
tool activity.
|
|
143
|
-
|
|
144
|
-
## CLI reference
|
|
145
|
-
|
|
146
|
-
```text
|
|
147
|
-
chivgent [options] "question" Answer one question and exit
|
|
148
|
-
chivgent [options] Start an interactive session
|
|
149
|
-
|
|
150
|
-
Options:
|
|
151
|
-
--provider NAME openai, deepseek, openai-compatible, openrouter, groq, xai,
|
|
152
|
-
moonshot (default: openai)
|
|
153
|
-
--model MODEL Provider model override
|
|
154
|
-
--max-turns N Tool-calling turn limit (default: 8, 16 with --allow-writes
|
|
155
|
-
or --allow-shell)
|
|
156
|
-
--no-stream Wait for the full answer instead of streaming tokens
|
|
157
|
-
-q, --quiet Hide tool activity on stderr
|
|
158
|
-
--json Write the run as JSON lines instead of rendered text
|
|
159
|
-
-c, --continue Resume the most recent session for this workspace
|
|
160
|
-
--resume ID Resume a specific session
|
|
161
|
-
--api-key KEY API key for this run; prefer an environment variable
|
|
162
|
-
--sessions List recorded sessions and exit
|
|
163
|
-
--allow-writes Let the agent create and change files (default: read-only)
|
|
164
|
-
--allow-shell Let the agent run shell commands. This implies write access:
|
|
165
|
-
a shell is not bound by the workspace. Unix only.
|
|
166
|
-
--serve Expose this session on a local socket and keep running
|
|
167
|
-
--connect TARGET Attach to a served session, by id or socket path
|
|
168
|
-
--servers List the servers still answering, then exit
|
|
169
|
-
--no-extensions Do not load any extension, and do not ask about trust
|
|
170
|
-
--extensions List loaded extensions and what they register, then exit
|
|
171
|
-
--forget-trust Forget the trust decision covering this workspace, then exit
|
|
172
|
-
--context-window N Token budget for the context (default: 128000)
|
|
173
|
-
--no-compaction Send the whole transcript instead of summarising old turns
|
|
174
|
-
--no-session Do not record this run
|
|
175
|
-
-h, --help Show help
|
|
176
|
-
-v, --version Show version
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
In an interactive session, `/help` lists the slash commands, including
|
|
180
|
-
`/provider`, `/model`, `/endpoint`, `/login`, `/session`, `/tools`, `/clear`, and `/exit`.
|
|
181
|
-
In the TUI, typing `/` opens an inline command menu; `/provider` opens a Provider picker
|
|
182
|
-
with Up/Down and Enter. Selecting a Provider without a saved key immediately asks for
|
|
183
|
-
its API key. Use `/login` later to replace a key. Ctrl+C stops a running answer;
|
|
184
|
-
at an idle prompt it exits with code 130. Ctrl+D also leaves the session.
|
|
185
|
-
|
|
186
|
-
Exit codes: `0` answered, `1` configuration or Provider failure, `2` turn limit
|
|
187
|
-
reached, `130` interrupted with Ctrl+C.
|
|
188
|
-
|
|
189
|
-
### Signing in
|
|
190
|
-
|
|
191
|
-
The quickest way in is to start chivgent and let it ask:
|
|
192
|
-
|
|
193
|
-
```text
|
|
194
|
-
$ chivgent --tui
|
|
195
|
-
v1.0.0
|
|
196
|
-
openai / gpt-5.6
|
|
197
|
-
Start with /provider → choose a Provider
|
|
198
|
-
› /provider deepseek
|
|
199
|
-
Selected deepseek / deepseek-v4-flash. API key needed for deepseek.
|
|
200
|
-
API key for deepseek (hidden, saved locally; Enter skips):
|
|
201
|
-
Stored the key for deepseek. Ready for your next prompt.
|
|
202
|
-
›
|
|
203
41
|
```
|
|
204
42
|
|
|
205
|
-
|
|
206
|
-
and enter its key when asked; the next prompt can use it immediately. An already
|
|
207
|
-
configured Provider skips this step. `/login` remains available to replace a key.
|
|
208
|
-
|
|
209
|
-
The key is not echoed as you type, and `auth.json` is written owner-only. It is
|
|
210
|
-
not verified against the Provider when stored; the first prompt after it is what
|
|
211
|
-
proves it works.
|
|
212
|
-
|
|
213
|
-
A non-interactive run still fails fast when no key is configured: a pipeline has
|
|
214
|
-
nobody to ask.
|
|
215
|
-
|
|
216
|
-
You can switch Providers and models without restarting or losing history:
|
|
217
|
-
|
|
218
|
-
```text
|
|
219
|
-
› /provider
|
|
220
|
-
› /provider deepseek
|
|
221
|
-
› /model deepseek-v4-pro
|
|
222
|
-
› /provider openrouter
|
|
223
|
-
› /model anthropic/claude-sonnet-4
|
|
224
|
-
› /provider openai-compatible
|
|
225
|
-
› /model vendor-model
|
|
226
|
-
› /endpoint https://api.vendor.example/v1
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
In the TUI, a newly selected Provider asks for its key if none is configured.
|
|
230
|
-
For Providers that also need a model or endpoint, the key can be stored first.
|
|
231
|
-
|
|
232
|
-
`--api-key` remains scoped to the Provider selected at startup; it is never
|
|
233
|
-
reused for a different Provider.
|
|
234
|
-
Switching from OpenAI to a custom compatible endpoint also does not reuse
|
|
235
|
-
`OPENAI_API_KEY`; the TUI asks for that endpoint's own key.
|
|
236
|
-
|
|
237
|
-
### Provider configuration
|
|
238
|
-
|
|
239
|
-
| Provider | API key | Model environment variable | Default model | API style |
|
|
240
|
-
| --- | --- | --- | --- | --- |
|
|
241
|
-
| OpenAI | `OPENAI_API_KEY` | `OPENAI_MODEL` | `gpt-5.6` | Responses API |
|
|
242
|
-
| DeepSeek | `DEEPSEEK_API_KEY` | `DEEPSEEK_MODEL` | `deepseek-v4-flash` | OpenAI-compatible Chat Completions |
|
|
243
|
-
| Custom compatible | `OPENAI_API_KEY` | `OPENAI_MODEL` | Required | OpenAI-compatible Chat Completions |
|
|
244
|
-
| OpenRouter | `OPENROUTER_API_KEY` | `OPENROUTER_MODEL` | Required | OpenAI-compatible Chat Completions |
|
|
245
|
-
| Groq | `GROQ_API_KEY` | `GROQ_MODEL` | Required | OpenAI-compatible Chat Completions |
|
|
246
|
-
| xAI | `XAI_API_KEY` | `XAI_MODEL` | Required | OpenAI-compatible Chat Completions |
|
|
247
|
-
| Moonshot | `MOONSHOT_API_KEY` | `MOONSHOT_MODEL` | Required | OpenAI-compatible Chat Completions |
|
|
248
|
-
|
|
249
|
-
An explicit `--model` value takes precedence over the Provider-specific model
|
|
250
|
-
environment variable. Custom compatible Providers also require
|
|
251
|
-
`OPENAI_BASE_URL`. Sessions are written under `CHIVGENT_HOME` (default
|
|
252
|
-
`~/.chivgent`).
|
|
253
|
-
|
|
254
|
-
Providers are declared in a registry rather than branched on in the CLI, so
|
|
255
|
-
`--help` and `--provider` validation are generated from the same list that
|
|
256
|
-
creates the client.
|
|
257
|
-
|
|
258
|
-
#### API key resolution
|
|
259
|
-
|
|
260
|
-
Keys are resolved in this order, first match wins:
|
|
261
|
-
|
|
262
|
-
1. `--api-key` for a single run
|
|
263
|
-
2. the Provider's environment variable
|
|
264
|
-
3. `<CHIVGENT_HOME>/auth.json`
|
|
265
|
-
|
|
266
|
-
An environment variable deliberately beats the stored file, matching the
|
|
267
|
-
convention other CLIs use, so a stored key can be overridden for one run
|
|
268
|
-
without editing anything.
|
|
269
|
-
|
|
270
|
-
`auth.json` is optional and holds literal keys only:
|
|
271
|
-
|
|
272
|
-
```json
|
|
273
|
-
{
|
|
274
|
-
"openai": { "type": "api_key", "key": "sk-..." },
|
|
275
|
-
"deepseek": "sk-..."
|
|
276
|
-
}
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
Neither `$VAR` expansion nor `!command` substitution is supported: letting a
|
|
280
|
-
config file spawn a process is a large attack surface for a small convenience.
|
|
281
|
-
chivgent warns when the file is readable by other users; keep it at `chmod 600`.
|
|
43
|
+
No key is required to open the session. Type `/provider` and enter one when asked, or export one first. Keys are saved for your user only, in `~/.chivgent/auth.json`.
|
|
282
44
|
|
|
283
45
|
```bash
|
|
284
|
-
|
|
285
|
-
chivgent --provider deepseek --model deepseek-v4-pro "Explain package.json"
|
|
286
|
-
chivgent --provider openai-compatible --model vendor-model "Explain package.json"
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
## Architecture
|
|
290
|
-
|
|
291
|
-
```text
|
|
292
|
-
+-> OpenAI Responses API
|
|
293
|
-
User -> CLI -> Agent -> LLMClient |
|
|
294
|
-
| +-> OpenAI-compatible Chat -> DeepSeek / custom
|
|
295
|
-
|
|
|
296
|
-
+-> Tool Registry -> list_files / search_text / read_file -> Workspace
|
|
297
|
-
| write_file / edit_file (--allow-writes)
|
|
298
|
-
| bash (--allow-shell) -> ShellOperations
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
The Agent runtime owns its own messages. Provider-specific schemas are converted
|
|
302
|
-
only at the `LLMClient` boundary:
|
|
303
|
-
|
|
304
|
-
```text
|
|
305
|
-
Agent Message[] -> Provider adapter -> Provider request
|
|
306
|
-
<- Provider response
|
|
307
|
-
AssistantMessage <- normalized result
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
This prevents the Agent, tools, and CLI from depending on one vendor's message
|
|
311
|
-
format.
|
|
312
|
-
|
|
313
|
-
### Context management
|
|
314
|
-
|
|
315
|
-
A session records everything that happened. The context manager decides what
|
|
316
|
-
is worth sending for one request. Keeping those apart is what lets a long
|
|
317
|
-
session stay inside a fixed context window.
|
|
318
|
-
|
|
319
|
-
```text
|
|
320
|
-
Full transcript ──────────────→ Session store (what happened)
|
|
321
|
-
│
|
|
322
|
-
↓
|
|
323
|
-
ContextManager
|
|
324
|
-
│ token estimate vs. contextWindow - reserveTokens
|
|
325
|
-
↓
|
|
326
|
-
summary + recent messages ────→ Provider (what the model sees)
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
When the estimate exceeds the budget, older messages are summarised into a
|
|
330
|
-
single message and recent turns are kept verbatim. Three details matter:
|
|
331
|
-
|
|
332
|
-
- **File lists are derived from tool calls, not from the summary.** A summary
|
|
333
|
-
can forget or invent a path. For a coding agent, "which files did I read and
|
|
334
|
-
change" is the part that most needs to survive intact, so it is collected
|
|
335
|
-
from the `read_file`, `write_file`, and `edit_file` calls themselves.
|
|
336
|
-
- **Tool calls are never separated from their results.** A split point that
|
|
337
|
-
would orphan a tool result moves forward past the whole group.
|
|
338
|
-
- **Compaction discards the Provider continuation.** A Provider that chains
|
|
339
|
-
history server-side replays its own copy and ignores the messages sent with
|
|
340
|
-
it, so keeping the continuation would send back the history just removed.
|
|
341
|
-
|
|
342
|
-
Token counts are estimated from character length rather than with a real
|
|
343
|
-
tokenizer, which would be model-specific and a large dependency for a number
|
|
344
|
-
that only decides *when* to compact. The reserve budget absorbs the error.
|
|
345
|
-
|
|
346
|
-
A single tool result larger than the whole budget cannot be compacted away;
|
|
347
|
-
bound tool output instead. Compaction is disabled with `--no-compaction`.
|
|
348
|
-
|
|
349
|
-
### Runtime events
|
|
350
|
-
|
|
351
|
-
The Agent Loop reports what it is doing through a typed event stream instead of
|
|
352
|
-
printing anything itself. One run emits:
|
|
353
|
-
|
|
354
|
-
```text
|
|
355
|
-
agent_start
|
|
356
|
-
turn_start -> message_start -> message_update* -> message_end
|
|
357
|
-
tool_execution_start -> tool_execution_end (once per tool call)
|
|
358
|
-
turn_end
|
|
359
|
-
...
|
|
360
|
-
agent_end (completed | max_turns | aborted | error)
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
`message_update` carries deltas only, never a cumulative snapshot, so the stream
|
|
364
|
-
stays linear in the length of the answer. Events are structured-cloneable and
|
|
365
|
-
each listener receives a copy, so a renderer can never mutate the transcript.
|
|
366
|
-
The CLI renderer in `src/render.ts` is one consumer; a log file, a JSON stream,
|
|
367
|
-
or a TUI are others.
|
|
368
|
-
|
|
369
|
-
`LLMClient.stream` is optional. When a Provider does not implement it, the Agent
|
|
370
|
-
falls back to `complete` and the same events are emitted without deltas.
|
|
371
|
-
|
|
372
|
-
### OpenAI-compatible Providers
|
|
373
|
-
|
|
374
|
-
Compatible Providers reuse the official `openai` npm package by changing
|
|
375
|
-
`baseURL`, credentials, and model. CLI users do not need to edit code:
|
|
376
|
-
|
|
377
|
-
```bash
|
|
378
|
-
export OPENAI_API_KEY="your-provider-api-key"
|
|
379
|
-
export OPENAI_BASE_URL="https://api.vendor.example/v1"
|
|
380
|
-
export OPENAI_MODEL="vendor-model"
|
|
381
|
-
|
|
382
|
-
chivgent --provider openai-compatible "What does src/agent.ts do?"
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
`OPENAI_BASE_URL` must point to the Provider's OpenAI-compatible API root. The
|
|
386
|
-
Provider must implement `POST /chat/completions` and function tool calling.
|
|
387
|
-
|
|
388
|
-
When adding a named Provider in source code, use the same adapter:
|
|
389
|
-
|
|
390
|
-
```ts
|
|
391
|
-
const client = new OpenAICompatibleChatClient({
|
|
392
|
-
apiKey: process.env.VENDOR_API_KEY!,
|
|
393
|
-
baseURL: "https://api.vendor.example/v1",
|
|
394
|
-
model: "vendor-model",
|
|
395
|
-
continuationTag: "vendor-chat",
|
|
396
|
-
});
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
`DeepSeekChatClient` is a small configuration wrapper around this shared client.
|
|
400
|
-
The compatibility layer also preserves optional Provider-only fields such as
|
|
401
|
-
DeepSeek's `reasoning_content` inside opaque continuation state.
|
|
402
|
-
|
|
403
|
-
Changing only `baseURL` is not a promise of complete compatibility. Providers
|
|
404
|
-
can differ in model names, authentication, tool-schema support, strict mode,
|
|
405
|
-
reasoning fields, streaming events, and error behavior. Keep those differences
|
|
406
|
-
inside thin Provider adapters rather than leaking them into the Agent loop.
|
|
407
|
-
|
|
408
|
-
## Project structure
|
|
409
|
-
|
|
410
|
-
```text
|
|
411
|
-
src/
|
|
412
|
-
cli.ts CLI entry point and process boundary
|
|
413
|
-
cli-options.ts Argument and Provider configuration
|
|
414
|
-
auth/
|
|
415
|
-
credentials.ts Credential contract and resolution order
|
|
416
|
-
runtime-credentials.ts --api-key override
|
|
417
|
-
env-credentials.ts Environment variable lookup
|
|
418
|
-
file-credentials.ts The auth.json store, read and write
|
|
419
|
-
agent.ts Agent loop and run state
|
|
420
|
-
events.ts Runtime event model
|
|
421
|
-
render.ts Terminal renderer for runtime events
|
|
422
|
-
llm.ts Provider-independent LLM contract
|
|
423
|
-
retry.ts Provider timeout and retry decorator
|
|
424
|
-
messages.ts Runtime message model
|
|
425
|
-
session.ts Conversation state and event fan-out
|
|
426
|
-
session-store.ts JSONL session log and resume support
|
|
427
|
-
repl.ts Interactive prompt and slash commands
|
|
428
|
-
context/
|
|
429
|
-
context-manager.ts Builds the messages for one request
|
|
430
|
-
compaction.ts Summarises old history and tracks files
|
|
431
|
-
token-estimator.ts Character-based token approximation
|
|
432
|
-
workspace.ts Workspace configuration and the read-only default
|
|
433
|
-
workspace/
|
|
434
|
-
types.ts Limits, errors, and the Workspace contract
|
|
435
|
-
paths.ts Path normalisation and escape protection
|
|
436
|
-
ignore.ts .gitignore and generated-directory filtering
|
|
437
|
-
text.ts UTF-8 decoding, line splitting, previews
|
|
438
|
-
read.ts Ranged reads
|
|
439
|
-
list.ts Directory walking
|
|
440
|
-
search.ts Literal text search
|
|
441
|
-
write.ts Atomic whole-file writes and exact edits
|
|
442
|
-
providers/
|
|
443
|
-
registry.ts Provider registry
|
|
444
|
-
usage.ts Reading and adding up Provider token counts
|
|
445
|
-
deferred-client.ts A client whose Provider can arrive later
|
|
446
|
-
definitions.ts Built-in Provider declarations
|
|
447
|
-
client.ts Credential resolution into an LLM client
|
|
448
|
-
openai.ts OpenAI Responses adapter
|
|
449
|
-
openai-compatible-chat.ts Shared Chat Completions adapter
|
|
450
|
-
deepseek.ts DeepSeek configuration wrapper
|
|
451
|
-
tools/
|
|
452
|
-
tool.ts Tool contract
|
|
453
|
-
output.ts Shared 64 KiB tool-output boundary
|
|
454
|
-
list-files.ts Deterministic project-tree discovery
|
|
455
|
-
search-text.ts Bounded literal source search
|
|
456
|
-
read-file.ts Ranged text-file reader
|
|
457
|
-
write-file.ts Whole-file create and replace
|
|
458
|
-
edit-file.ts Exact unique-match edit
|
|
459
|
-
bash.ts Shell command execution
|
|
460
|
-
prompts.ts The instructions the agent runs under
|
|
461
|
-
evals/
|
|
462
|
-
task.ts Task definitions and their validation
|
|
463
|
-
fixture.ts A fresh workspace copy per attempt
|
|
464
|
-
graders.ts Deterministic graders
|
|
465
|
-
runner.ts Runs a task N times and aggregates
|
|
466
|
-
report.ts Table and JSON output
|
|
467
|
-
parse-args.ts Eval CLI arguments
|
|
468
|
-
cli.ts npm run eval
|
|
469
|
-
remote/
|
|
470
|
-
protocol.ts Message shapes and version negotiation
|
|
471
|
-
framing.ts JSON Lines framing with a bounded buffer
|
|
472
|
-
server.ts Serves one session on a Unix socket
|
|
473
|
-
client.ts Attaches to a served session
|
|
474
|
-
repl.ts The interactive loop for an attached client
|
|
475
|
-
socket-path.ts Socket paths, staleness, and discovery
|
|
476
|
-
extensions/
|
|
477
|
-
trust.ts Per-directory trust store
|
|
478
|
-
decide-trust.ts The prompt, and the refusal when nobody can answer
|
|
479
|
-
discover.ts Where extensions live and which files count
|
|
480
|
-
api.ts What an extension may register
|
|
481
|
-
registry.ts Collects registrations, rejects conflicts
|
|
482
|
-
loader.ts Imports modules and contains their failures
|
|
483
|
-
shell/
|
|
484
|
-
types.ts Execution contract and shell error types
|
|
485
|
-
config.ts Shell resolution and the Windows guard
|
|
486
|
-
local.ts Local spawn backend
|
|
487
|
-
process.ts Process-group kill and exit handling
|
|
488
|
-
output.ts Bounded streaming output accumulator
|
|
489
|
-
truncate.ts Tail truncation for command output
|
|
490
|
-
sanitize.ts Control-character filtering
|
|
491
|
-
tests/ Provider, loop, and workspace tests
|
|
492
|
-
evals/ Eval tasks and their fixtures
|
|
493
|
-
docs/ Architecture and learning notes
|
|
46
|
+
export OPENAI_API_KEY="your-api-key"
|
|
494
47
|
```
|
|
495
48
|
|
|
496
|
-
|
|
49
|
+
In a session, `/login oauth openai` or `/login oauth xai` signs in with a subscription. On a normal start, a key still takes precedence. [Subscription sign-in](docs/subscription-oauth.md).
|
|
497
50
|
|
|
498
51
|
```bash
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
52
|
+
chivgent "Where is the entry point?" # reads, then answers
|
|
53
|
+
chivgent --permission-mode workspace "Run tests and fix them"
|
|
54
|
+
chivgent --permission-mode ask-first "Review this project"
|
|
55
|
+
chivgent --allow-writes "Rename sayHi to greet" # older flag, not with a mode
|
|
56
|
+
chivgent --allow-shell "Run the tests" # asks, then Seatbelt or Docker
|
|
57
|
+
chivgent --provider deepseek "Explain src/"
|
|
58
|
+
chivgent --tui # live region, multi-line editor
|
|
59
|
+
chivgent --continue # last session in this directory
|
|
503
60
|
```
|
|
504
61
|
|
|
505
|
-
|
|
62
|
+
## Modes
|
|
506
63
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
64
|
+
| Mode | What proceeds | This build |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| `workspace` | Workspace edits and sandboxed commands. Network stays off. A command that needs the host asks once, for that command only. | The auto-style default we want. Opt in with `--permission-mode workspace`. |
|
|
67
|
+
| `ask-first` | Reads. Each file change and each command asks. No answer means no action. | `--permission-mode ask-first` |
|
|
68
|
+
| `unrestricted` | Shell commands run with broad host file access and network, inside the OS sandbox. File tools stay in the workspace. | Explicit opt-in. |
|
|
69
|
+
| none | Reads. Writes and shell wait for a flag. Each command asks. | What `chivgent` does now. |
|
|
510
70
|
|
|
511
|
-
|
|
71
|
+
`--permission-mode` replaces the flags for this process. It cannot be combined with `--allow-writes`, `--allow-shell`, `--approve-all-shell`, or `--shell-network`, and it cannot be used with `--serve` or `--connect`. `/permissions` inspects or changes the mode, only in a session that started with one. The choice is not saved in the transcript. Resuming a session uses the mode you selected at startup, not a broader one from last time.
|
|
512
72
|
|
|
513
|
-
|
|
514
|
-
npm pack
|
|
515
|
-
npm install -g ./chivgent-0.6.0.tgz
|
|
516
|
-
```
|
|
73
|
+
`/plan` is separate. It keeps the agent on read tools and a plan. Writes, shell, and extension tools stay blocked even if the model asks for them.
|
|
517
74
|
|
|
518
|
-
|
|
519
|
-
manual so the default test suite never consumes credits.
|
|
75
|
+
## How it fits together
|
|
520
76
|
|
|
521
|
-
|
|
77
|
+
You type in the terminal. chivgent calls the provider you picked. File tools stay inside the current directory. The shell runs in a sandbox and does not receive your provider keys. On the default start, the shell is off until you turn it on.
|
|
522
78
|
|
|
523
|
-
|
|
524
|
-
|
|
79
|
+
<picture>
|
|
80
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/fit-dark.svg">
|
|
81
|
+
<img src="docs/assets/fit-light.svg" width="920" alt="The default start: you, chivgent, the provider you picked, this directory, and a sandbox only if shell is on.">
|
|
82
|
+
</picture>
|
|
525
83
|
|
|
526
|
-
|
|
527
|
-
npm run eval # every task in evals/
|
|
528
|
-
npm run eval -- --task rename-symbol --attempts 10
|
|
529
|
-
npm run eval -- --allow-writes --allow-shell --json report.json
|
|
530
|
-
DEEPSEEK_API_KEY=sk-... npm run eval -- --provider deepseek
|
|
531
|
-
```
|
|
84
|
+
## What it can touch
|
|
532
85
|
|
|
533
|
-
|
|
534
|
-
fully expanded command before running it, so a key on the command line lands in
|
|
535
|
-
the clear in any captured log.
|
|
86
|
+
This is the build, not the auto-style default above.
|
|
536
87
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
88
|
+
| | How | What it can reach |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| Read the project | on | This directory. Ignored, generated, and credential paths are skipped. |
|
|
91
|
+
| Change files | `--allow-writes` | Files inside the workspace. An edit has to match exactly, and it is written atomically. |
|
|
92
|
+
| Run a command | `--allow-shell` | Seatbelt on macOS, Docker elsewhere. Network is off. Each command requires confirmation. |
|
|
93
|
+
| Pick a policy | `--permission-mode` | `ask-first`, `workspace`, or `unrestricted`. Replaces the flags for this process. |
|
|
541
94
|
|
|
542
|
-
|
|
95
|
+
You pay the provider you picked, at their prices. chivgent shows token counts; it does not convert them into costs.
|
|
543
96
|
|
|
544
|
-
|
|
545
|
-
```
|
|
97
|
+
## Providers
|
|
546
98
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
ten trains everyone to ignore CI. `npm test` stays free, offline and
|
|
557
|
-
deterministic.
|
|
558
|
-
|
|
559
|
-
A task is a directory under `evals/`: a `task.json` and a `fixture/` tree copied
|
|
560
|
-
into a fresh temporary workspace for every attempt.
|
|
561
|
-
|
|
562
|
-
```jsonc
|
|
563
|
-
{
|
|
564
|
-
"prompt": "Rename the function sayHi to greet everywhere, including callers.",
|
|
565
|
-
"capabilities": ["writes"],
|
|
566
|
-
"attempts": 5,
|
|
567
|
-
"graders": [
|
|
568
|
-
{ "type": "file-contains", "path": "src/greet.ts", "text": "export function greet(" },
|
|
569
|
-
{ "type": "file-excludes", "path": "src/greet.ts", "text": "sayHi" },
|
|
570
|
-
{ "type": "used-tool", "name": "edit_file" },
|
|
571
|
-
{ "type": "not-used-tool", "name": "write_file" }
|
|
572
|
-
]
|
|
573
|
-
}
|
|
574
|
-
```
|
|
99
|
+
| Provider | `--provider` | Key | Model |
|
|
100
|
+
| --- | --- | --- | --- |
|
|
101
|
+
| OpenAI, Responses API | `openai` (default) | `OPENAI_API_KEY` | `gpt-5.6` |
|
|
102
|
+
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek-v4-flash` |
|
|
103
|
+
| Any compatible endpoint | `openai-compatible` | `OPENAI_API_KEY` and `OPENAI_BASE_URL` | set `OPENAI_MODEL` |
|
|
104
|
+
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` | set `OPENROUTER_MODEL` |
|
|
105
|
+
| Groq | `groq` | `GROQ_API_KEY` | set `GROQ_MODEL` |
|
|
106
|
+
| xAI | `xai` | `XAI_API_KEY` | set `XAI_MODEL` |
|
|
107
|
+
| Moonshot | `moonshot` | `MOONSHOT_API_KEY` | set `MOONSHOT_MODEL` |
|
|
575
108
|
|
|
576
|
-
|
|
577
|
-
counts. There is no LLM judge: a judge is itself a nondeterministic instrument,
|
|
578
|
-
and measuring a nondeterministic subject with one compounds the error until "the
|
|
579
|
-
agent got worse" cannot be told apart from "the judge felt different today".
|
|
580
|
-
|
|
581
|
-
Those last two graders are the point. Rewriting the whole file also produces the
|
|
582
|
-
right contents, and an eval that scores results alone would give it full marks.
|
|
583
|
-
For a coding agent, tool misuse is the more common and the more interesting
|
|
584
|
-
failure, so tasks assert on how the work was done.
|
|
585
|
-
|
|
586
|
-
A grader naming a tool the task never grants is refused when the task loads.
|
|
587
|
-
`not-used-tool: write_file` on a read-only task cannot fail — it asserts the
|
|
588
|
-
model did not call something it was never given — and its mirror image cannot
|
|
589
|
-
pass. Both are task-definition mistakes, and both are caught before the run
|
|
590
|
-
spends anything. One such grader shipped for two releases before this check
|
|
591
|
-
existed.
|
|
592
|
-
|
|
593
|
-
Three graders exist because a set of tool names cannot answer the question they
|
|
594
|
-
answer. `tool-never-failed` catches a guessed path, which shows up as a failed
|
|
595
|
-
read that a deduplicated name list hides — it is sound only where a failed call
|
|
596
|
-
means the model was wrong, so it fits `read_file` and not `bash`, which reports
|
|
597
|
-
any non-zero exit as an error and is *supposed* to fail on a task that runs a
|
|
598
|
-
failing test. `max-tool-calls` budgets calls rather than turns, because a model
|
|
599
|
-
may issue any number of calls in one turn: "did it follow the imports or read
|
|
600
|
-
the whole project" is a call count. `file-unchanged` compares against the
|
|
601
|
-
fixture, so "don't touch what you weren't asked to touch" becomes a verdict
|
|
602
|
-
rather than an intention — and it needs no second copy of the file in
|
|
603
|
-
`task.json` to drift out of date. The JSON report carries `toolCalls`, every
|
|
604
|
-
call in order with whether it succeeded, alongside the `toolsUsed` set the table
|
|
605
|
-
prints.
|
|
606
|
-
|
|
607
|
-
The nine tasks split into what the agent found and what it changed. Four exist
|
|
608
|
-
because the first real baseline passed 29 of 30 attempts and therefore measured
|
|
609
|
-
nothing: `needle-in-many-files` (40 files with uninformative names, so listing
|
|
610
|
-
gives no signal), `trace-the-default` (a value overridden twice, where stopping
|
|
611
|
-
at the first hop yields a plausible wrong number), `decoy-config` (two
|
|
612
|
-
near-identical modules, one of them dead), and `wrong-test` (a failing test
|
|
613
|
-
whose expectation contradicts the contract documented in the source — bending
|
|
614
|
-
the source to fit it is the trap).
|
|
615
|
-
|
|
616
|
-
A task that scores 0/N or N/N across different models is not measuring anything
|
|
617
|
-
and should be made harder, fixed, or dropped. Passing is not evidence of quality
|
|
618
|
-
when everything passes.
|
|
619
|
-
|
|
620
|
-
## Token usage
|
|
621
|
-
|
|
622
|
-
Providers report what each call cost, and chivgent now keeps it: per turn on
|
|
623
|
-
`message_end`, per run on `agent_end` and the run result, per attempt in the
|
|
624
|
-
eval report, and cumulatively in `/session`.
|
|
625
|
-
|
|
626
|
-
```text
|
|
627
|
-
› /session
|
|
628
|
-
id: 2026-09-07T...
|
|
629
|
-
workspace: /home/me/project
|
|
630
|
-
prompts: 4
|
|
631
|
-
messages: 18
|
|
632
|
-
tokens: 38.2k total, 35.9k in, 2.3k out, 12.0k cached
|
|
633
|
-
```
|
|
109
|
+
`--model` overrides the model variable. Keys resolve in this order: `--api-key`, then the environment variable, then `~/.chivgent/auth.json`. A custom base URL receives your key and your prompts. Point it only at an endpoint you trust.
|
|
634
110
|
|
|
635
|
-
|
|
636
|
-
table, and that table goes stale silently when a Provider changes its rates —
|
|
637
|
-
producing a figure that looks precise and is wrong, which is worse than no
|
|
638
|
-
figure because nobody questions a number with a decimal point in it. Token
|
|
639
|
-
counts are what the Provider itself reported and do not expire.
|
|
640
|
-
|
|
641
|
-
A total is marked incomplete when some call reported nothing, rather than
|
|
642
|
-
counting it as zero: a missing figure stays visibly missing instead of quietly
|
|
643
|
-
understating the total. Compaction's own summarising call is included, since it
|
|
644
|
-
trades a call now against smaller inputs later and that trade cannot be judged
|
|
645
|
-
with half of it hidden.
|
|
646
|
-
|
|
647
|
-
Streamed Chat Completions only report usage when asked, so chivgent sends
|
|
648
|
-
`stream_options: { include_usage: true }`. A self-hosted OpenAI-compatible
|
|
649
|
-
endpoint that predates that field may reject the request; `--no-stream` is the
|
|
650
|
-
fallback.
|
|
651
|
-
|
|
652
|
-
## The live region
|
|
653
|
-
|
|
654
|
-
`--tui` draws a status region above the prompt while a run is in progress: the
|
|
655
|
-
turn, whether the model is thinking or running tools, which tools are running
|
|
656
|
-
with what they are aimed at and their newest output, elapsed time, and the
|
|
657
|
-
running token count. Long single-line replies keep their newest text visible;
|
|
658
|
-
long paths retain the filename and tool progress. On narrow terminals, the
|
|
659
|
-
status and stop shortcut take priority.
|
|
660
|
-
|
|
661
|
-
```text
|
|
662
|
-
Let me look at how sessions are stored.
|
|
663
|
-
read_file src/session.ts (2s)
|
|
664
|
-
search_text (1s) src/store.ts:41: export class SessionStore
|
|
665
|
-
running tools · turn 2/8 · 11s · 4.2k tokens · ctrl+c to stop
|
|
666
|
-
```
|
|
111
|
+
A compatible endpoint must implement `POST /chat/completions` with tool calling. Changing the base URL does not guarantee full compatibility. [Architecture](docs/architecture.md#openai-compatible-providers).
|
|
667
112
|
|
|
668
|
-
|
|
669
|
-
one — streamed output, the session log, extensions, the remote client — is
|
|
670
|
-
append-only: an event arrives, it is printed, it is forgotten. This one has to
|
|
671
|
-
rebuild *what is happening now* from the same stream and keep it right as more
|
|
672
|
-
arrives, which splits into three pieces:
|
|
113
|
+
## A session you can come back to
|
|
673
114
|
|
|
674
|
-
|
|
675
|
-
reduce(state, event, now) -> ViewState pure
|
|
676
|
-
view(state, {width, now}) -> string[] pure
|
|
677
|
-
paint(previous, next) the only part that touches a terminal
|
|
678
|
-
```
|
|
115
|
+
Run `chivgent` with no question for an interactive session. It is saved under `~/.chivgent/sessions`. `--continue` resumes the latest one in this directory. `/resume` lists the others, and only opens sessions from here.
|
|
679
116
|
|
|
680
|
-
|
|
681
|
-
guarantees live. One asymmetry in the event vocabulary is what makes the state
|
|
682
|
-
model load-bearing: `message_update` carries a **delta**, `tool_execution_update`
|
|
683
|
-
carries a truncated **snapshot**. Appending a snapshot stacks output that was
|
|
684
|
-
never produced — the window has already had its front dropped — and replacing on
|
|
685
|
-
a delta leaves the last token and loses the answer. An append-only renderer
|
|
686
|
-
never has to know the difference, because it just prints whatever arrives. Two
|
|
687
|
-
tests fail when either is written the wrong way round.
|
|
688
|
-
|
|
689
|
-
It does not take the alternate screen buffer. That would cost the scrollback,
|
|
690
|
-
and getting it back means reimplementing scrolling, search and selection —
|
|
691
|
-
thousands of lines that teach terminal graphics rather than agent architecture.
|
|
692
|
-
A finished turn is flushed to the terminal's own scrollback and dropped from
|
|
693
|
-
the state, so a long session never grows it. Input stays with readline for the
|
|
694
|
-
same reason: a line editor is not the interesting problem here.
|
|
695
|
-
|
|
696
|
-
Painting rewrites only the lines whose content changed, so a ticking timer
|
|
697
|
-
costs one line rather than a repaint. A resize invalidates that baseline — the
|
|
698
|
-
terminal has reflowed what is on screen — and is the one moment a full repaint
|
|
699
|
-
is correct rather than lazy.
|
|
700
|
-
|
|
701
|
-
`--tui` needs a terminal on stdin and stderr and an interactive session; it
|
|
702
|
-
refuses rather than falling back silently, since a switch that quietly does
|
|
703
|
-
nothing makes a mistyped command look like it worked. It is not the default
|
|
704
|
-
yet. The startup wordmark shows the Provider, model, workspace and next action;
|
|
705
|
-
use `/session` for the session id. Type `/` to open the inline command menu
|
|
706
|
-
(including extension commands); Up/Down selects, Tab completes, and Enter runs.
|
|
707
|
-
Outside a menu, Up/Down browses input history. During a run ordinary typing is ignored; Ctrl+C cancels immediately.
|
|
708
|
-
At an idle prompt Ctrl+C exits, clearing the draft and returning the terminal
|
|
709
|
-
to the shell. Ctrl+D on an empty line also exits.
|
|
710
|
-
Input is single-line: only the first submitted line in an input batch is accepted.
|
|
711
|
-
Wait for the prompt before sending another question.
|
|
712
|
-
After cancellation the prompt is ready again and partial text stays in scrollback.
|
|
713
|
-
A completion line records the outcome, elapsed time and reported token usage.
|
|
714
|
-
|
|
715
|
-
Chinese, combining characters and joined emoji are clipped by terminal columns;
|
|
716
|
-
short terminals keep the status visible. Resizing repaints the existing region.
|
|
717
|
-
All prompts and UI output go to stderr; stdout receives final answers only, so
|
|
718
|
-
`chivgent --tui > answers.txt` keeps the terminal interactive while saving answers.
|
|
719
|
-
|
|
720
|
-
```sh
|
|
721
|
-
npm run build
|
|
722
|
-
node dist/cli.js --tui
|
|
723
|
-
npm run demo:tui # Offline interactive demo; no API key or network required
|
|
724
|
-
```
|
|
117
|
+
`/compact` summarizes older turns and keeps the full transcript to resume later. `/status` shows the model, the permissions, and token usage. `/help` lists the rest.
|
|
725
118
|
|
|
726
|
-
|
|
727
|
-
workspace. See [the TUI guide](docs/tui.md) for controls and verification.
|
|
119
|
+
`--tui` adds a live status region and a multi-line editor. [TUI](docs/tui-v5.md). A long session stays within the context window by summarizing older turns and keeping the list of files read and changed. [Context](docs/architecture.md#context-management).
|
|
728
120
|
|
|
729
|
-
##
|
|
121
|
+
## Boundaries
|
|
730
122
|
|
|
731
|
-
|
|
732
|
-
|
|
123
|
+
- Paths outside the workspace are rejected, including `..` and symlink escapes. Common credential paths are denied. Tool output is capped.
|
|
124
|
+
- With no mode selected, `--allow-shell` asks before each command. A headless or served session denies commands unless you also pass `--approve-all-shell`. If the sandbox cannot start, the command does not run unsandboxed.
|
|
125
|
+
- `workspace` runs workspace edits and sandboxed commands on its own, and asks once when a command wants host file and network access. `unrestricted` is the explicit opt-in for broad host access and network. Neither is saved with the session. [Shell safety](docs/shell-sandbox.md).
|
|
126
|
+
- The macOS sandbox can still read files your user can read. It restricts writes and network access. It is not confidentiality isolation.
|
|
127
|
+
- There is no per-command allowlist, and no native Windows shell. `workspace` is not the start mode of this build.
|
|
128
|
+
- Extensions are JavaScript in the chivgent process. Trusting a project means letting its authors run code as you. chivgent prompts once per directory, and does not load extensions when there is no terminal to prompt.
|
|
129
|
+
- Keys, subscription credentials, and session logs are owner-only and stored in plain text. Logs contain prompts, answers, and file excerpts.
|
|
130
|
+
- `--serve` puts the session on a Unix socket in an owner-only directory. Anyone who can open the socket gets every capability the server started with. There is no TCP listener.
|
|
733
131
|
|
|
734
|
-
|
|
735
|
-
# One terminal
|
|
736
|
-
chivgent --serve --allow-writes
|
|
737
|
-
# chivgent 0.12.0 serving session 2026-09-06T...
|
|
738
|
-
# socket: ~/.chivgent/sockets/2026-09-06T....sock
|
|
739
|
-
# capabilities: --allow-writes
|
|
740
|
-
|
|
741
|
-
# Another terminal
|
|
742
|
-
chivgent --servers # list what is running
|
|
743
|
-
chivgent --connect <id> # attach interactively
|
|
744
|
-
chivgent --connect <id> "question" # ask once and leave
|
|
745
|
-
```
|
|
132
|
+
Work on committed code. Use a copy for a repository you do not trust.
|
|
746
133
|
|
|
747
|
-
|
|
748
|
-
server broadcasts. Several clients can attach at once — the extra ones watch the
|
|
749
|
-
same run as it happens, and any of them can interrupt it, because the run
|
|
750
|
-
belongs to the session rather than to whoever started it. A prompt sent while
|
|
751
|
-
another is running is refused rather than queued, and a client that disconnects
|
|
752
|
-
mid-run does not cancel it.
|
|
753
|
-
|
|
754
|
-
Attaching does not replay history; the session log already holds that. The
|
|
755
|
-
protocol is JSON Lines over a Unix socket, one object per line, the same shape
|
|
756
|
-
`--json` writes.
|
|
757
|
-
|
|
758
|
-
**Whoever can reach the socket has everything the server was started with.** If
|
|
759
|
-
it was started with `--allow-shell`, anyone who can connect can make the model
|
|
760
|
-
run commands, which is why the server prints its capabilities on startup: the
|
|
761
|
-
person attaching cannot see the flags you typed. The boundary is filesystem
|
|
762
|
-
permissions — sockets live in an owner-only directory under `CHIVGENT_HOME` —
|
|
763
|
-
and there is no TCP listener. For another machine, forward the socket over SSH
|
|
764
|
-
so that authentication is SSH's job.
|
|
765
|
-
|
|
766
|
-
## Extensions
|
|
767
|
-
|
|
768
|
-
An extension is an ES module that default-exports a function. It is called once
|
|
769
|
-
at startup with an API that can add a tool, add a slash command, subscribe to
|
|
770
|
-
runtime events, and append to the system prompt.
|
|
771
|
-
|
|
772
|
-
```js
|
|
773
|
-
// .chivgent/extensions/word-count.js
|
|
774
|
-
export default function (api) {
|
|
775
|
-
api.registerTool({
|
|
776
|
-
name: "word_count",
|
|
777
|
-
description: "Count the words in a workspace file.",
|
|
778
|
-
inputSchema: {
|
|
779
|
-
type: "object",
|
|
780
|
-
properties: { path: { type: "string" } },
|
|
781
|
-
required: ["path"],
|
|
782
|
-
additionalProperties: false,
|
|
783
|
-
},
|
|
784
|
-
async execute(args, context) {
|
|
785
|
-
const file = await context.workspace.readTextFile(args.path);
|
|
786
|
-
return {
|
|
787
|
-
content: `${file.content.split(/\s+/).filter(Boolean).length} words`,
|
|
788
|
-
isError: false,
|
|
789
|
-
};
|
|
790
|
-
},
|
|
791
|
-
});
|
|
792
|
-
|
|
793
|
-
api.contributeSystemPrompt("Use word_count instead of reading a file to count words.");
|
|
794
|
-
}
|
|
795
|
-
```
|
|
134
|
+
This repository also has an Electron app, aimed at a local workbench on the same agent. The current build is a prototype. It is not how you use chivgent today. [Desktop plan](docs/desktop-architecture.md).
|
|
796
135
|
|
|
797
|
-
|
|
136
|
+
## Documentation
|
|
798
137
|
|
|
799
|
-
|
|
|
138
|
+
| | |
|
|
800
139
|
| --- | --- |
|
|
801
|
-
|
|
|
802
|
-
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
so an extension cannot shadow `read_file` or `/clear`, and a broken extension is
|
|
808
|
-
reported and skipped rather than taking chivgent down with it.
|
|
809
|
-
|
|
810
|
-
`chivgent --extensions` lists what loaded and what each one registered.
|
|
811
|
-
|
|
812
|
-
### Project trust
|
|
813
|
-
|
|
814
|
-
The first time you run chivgent in a project that ships extensions, it describes
|
|
815
|
-
what they are and asks once. The answer is stored in `<CHIVGENT_HOME>/trust.json`
|
|
816
|
-
against the resolved directory path, and matched by nearest ancestor, so trusting
|
|
817
|
-
`~/work` covers every repository under it. `--forget-trust` removes the decision
|
|
818
|
-
covering the current workspace.
|
|
819
|
-
|
|
820
|
-
**Trusting a project means letting its authors run code as you.** An extension
|
|
821
|
-
executes inside the chivgent process: it is not bound by the workspace, it does
|
|
822
|
-
not need `--allow-shell` to run a command, and it can read your environment
|
|
823
|
-
including the API key. That is why the question is asked before anything is
|
|
824
|
-
imported, and why the answer is no whenever there is nobody to ask — a CI job or
|
|
825
|
-
a piped run never loads a checkout's extensions on its own.
|
|
826
|
-
|
|
827
|
-
## Security model
|
|
828
|
-
|
|
829
|
-
- API keys come from `--api-key`, an environment variable, or an optional
|
|
830
|
-
`auth.json`, in that order, and must never be committed.
|
|
831
|
-
- `auth.json` stores keys in plain text. It is opt-in for that reason, and
|
|
832
|
-
chivgent warns when its permissions let other users read it.
|
|
833
|
-
- `/login` writes it owner-only and does not echo what you type, but the key is
|
|
834
|
-
still stored in plain text; it is a convenience, not a secret manager.
|
|
835
|
-
- The auth file accepts literal keys only; it cannot expand environment
|
|
836
|
-
variables or run shell commands.
|
|
837
|
-
- A custom `OPENAI_BASE_URL` receives the configured API key and prompts; use
|
|
838
|
-
only endpoints you trust.
|
|
839
|
-
- Workspace tools are read-only unless `--allow-writes` is passed; `write_file`
|
|
840
|
-
and `edit_file` are not registered at all without it.
|
|
841
|
-
- The `bash` tool needs `--allow-shell`, which is separate from `--allow-writes`
|
|
842
|
-
and never implied by it. Granting it grants far more: a shell can change or
|
|
843
|
-
delete anything the user running chivgent can, inside the workspace or not,
|
|
844
|
-
and none of the workspace limits below apply to it.
|
|
845
|
-
- Commands are spawned in their own process group and killed as a group, so
|
|
846
|
-
cancelling a run does not leave descendants behind.
|
|
847
|
-
- Commands inherit chivgent's environment, which includes the API key it is
|
|
848
|
-
using. A model with `--allow-shell` can read that key and anything else the
|
|
849
|
-
environment holds. Run it with an environment that carries only what the task
|
|
850
|
-
needs.
|
|
851
|
-
- Truncated command output is written to a temp file so the model can read the
|
|
852
|
-
rest. The file is owner-only, but it is not deleted when the run ends: it can
|
|
853
|
-
hold anything the command printed. Clear the temp directory after sensitive
|
|
854
|
-
work.
|
|
855
|
-
- Session logs record command output as well as file excerpts once
|
|
856
|
-
`--allow-shell` is on.
|
|
857
|
-
- Project extensions are loaded only after an explicit, recorded trust decision,
|
|
858
|
-
and never without a terminal to ask at. An extension runs in-process with your
|
|
859
|
-
permissions and is bound by none of the workspace limits above, so trusting a
|
|
860
|
-
project is the same order of authority as `--allow-shell`, reached by cloning
|
|
861
|
-
a repository rather than by typing a flag.
|
|
862
|
-
- User extensions under `<CHIVGENT_HOME>/extensions/` are always loaded; that
|
|
863
|
-
directory is your own configuration.
|
|
864
|
-
- Extensions cannot take the name of a built-in tool or command.
|
|
865
|
-
- `trust.json`, like the session log and the auth file, is written owner-only.
|
|
866
|
-
- A served session is reachable by anyone who can open its socket, and they get
|
|
867
|
-
every capability the server was started with. Sockets live in an owner-only
|
|
868
|
-
directory; the directory is the real gate, because a socket file exists
|
|
869
|
-
briefly with default permissions before it can be restricted.
|
|
870
|
-
- chivgent never listens on TCP. Use SSH forwarding to reach another machine.
|
|
871
|
-
- Writes resolve the deepest existing ancestor and reject a symlink at any
|
|
872
|
-
segment, so a planted link cannot redirect a write out of the workspace.
|
|
873
|
-
- Writes are staged in a sibling temp file and renamed into place, so an
|
|
874
|
-
interrupted write cannot truncate an existing file.
|
|
875
|
-
- `edit_file` refuses an edit whose `old_text` is missing or matches more than
|
|
876
|
-
once, so an imprecise edit fails instead of changing the wrong line.
|
|
877
|
-
- Paths must remain inside the current workspace.
|
|
878
|
-
- Real-path checks block `..` traversal and symlink escapes.
|
|
879
|
-
- File size and binary-content checks limit unsafe reads.
|
|
880
|
-
- Discovery respects the root `.gitignore` and fixed generated-directory ignores.
|
|
881
|
-
- Common credential and private-key paths are denied across all workspace tools.
|
|
882
|
-
- Tool results are limited to 64 KiB; reads, scans, depth, and result counts are bounded.
|
|
883
|
-
- Tool inputs are untrusted and validated before execution.
|
|
884
|
-
- The agent stops after a bounded number of model turns.
|
|
885
|
-
- Session logs under `~/.chivgent/sessions` contain prompts, answers, and tool
|
|
886
|
-
results, including file excerpts. Use `--no-session` in sensitive workspaces,
|
|
887
|
-
and treat the log directory like the project it describes.
|
|
888
|
-
- Session ids are validated before they become file paths.
|
|
889
|
-
|
|
890
|
-
This is an educational MVP, not a hardened sandbox. There is no permission
|
|
891
|
-
system: capabilities are coarse, session-level switches, and neither
|
|
892
|
-
`--allow-writes` nor `--allow-shell` asks for per-action confirmation. That is
|
|
893
|
-
deliberate. Once a shell exists, a command allowlist is bypassed by a single
|
|
894
|
-
`sh -c`, and a prompt on every action only trains people to approve without
|
|
895
|
-
reading, so chivgent states the boundary instead of pretending to enforce one.
|
|
896
|
-
|
|
897
|
-
Use these switches on work you have committed. If you need a real boundary,
|
|
898
|
-
put the whole process in a container and give that container only what the task
|
|
899
|
-
needs. Review the code and threat model before pointing chivgent at a sensitive
|
|
900
|
-
project.
|
|
901
|
-
|
|
902
|
-
## Roadmap
|
|
903
|
-
|
|
904
|
-
- [x] Minimal tool-calling agent loop
|
|
905
|
-
- [x] Safe `read_file` tool
|
|
906
|
-
- [x] OpenAI and DeepSeek Providers
|
|
907
|
-
- [x] Reusable OpenAI-compatible Chat Completions adapter
|
|
908
|
-
- [x] Custom OpenAI-compatible CLI Provider
|
|
909
|
-
- [x] Project discovery tools: `list_files`, `search_text`, and ranged `read_file`
|
|
910
|
-
- [x] Streaming output and runtime events
|
|
911
|
-
- [x] Persistent multi-turn sessions
|
|
912
|
-
- [x] Context-window management and compaction
|
|
913
|
-
- [x] Opt-in `write_file` and `edit_file` behind `--allow-writes`
|
|
914
|
-
- [x] Provider registry and credential resolution chain
|
|
915
|
-
- [x] `bash` tool with streaming output, behind `--allow-shell`
|
|
916
|
-
- [x] Extensions and project trust
|
|
917
|
-
- [x] Remote sessions over a local socket
|
|
918
|
-
- [x] An eval suite with deterministic graders and pass rates
|
|
919
|
-
- [x] Token usage from the Provider, aggregated per run and per eval
|
|
920
|
-
- [x] A live status region driven by the event stream (`--tui`)
|
|
921
|
-
|
|
922
|
-
Per-command confirmation prompts and command allowlists are deliberately not
|
|
923
|
-
planned. Once a shell tool exists, `bash` can do anything `write_file` can and
|
|
924
|
-
more, so an allowlist is bypassed by a single `sh -c` and a per-command prompt
|
|
925
|
-
only trains people to approve without reading. Capabilities are coarse,
|
|
926
|
-
session-level switches; the real boundary is a container.
|
|
140
|
+
| [Architecture](docs/architecture.md) | The loop, providers, context, and where the source lives |
|
|
141
|
+
| [Shell safety](docs/shell-sandbox.md) | Seatbelt, Docker, and what a command can still read |
|
|
142
|
+
| [Subscription sign-in](docs/subscription-oauth.md) | ChatGPT and xAI: what is stored, and what a key still does |
|
|
143
|
+
| [TUI](docs/tui-v5.md) | The live region, the editor, and diff review |
|
|
144
|
+
| [Evals](docs/evals.md) | Whether the agent finishes the task, separate from the unit tests |
|
|
145
|
+
| [Extensions and remote sessions](docs/extensions-and-remote.md) | Tools you add, and attaching another terminal |
|
|
927
146
|
|
|
928
|
-
##
|
|
929
|
-
|
|
930
|
-
- [Stage 1: Minimal Agent design](docs/stage-1-minimal-agent.md)
|
|
931
|
-
- [DeepSeek Provider design](docs/deepseek-provider.md)
|
|
932
|
-
- [Stage 2: Project Discovery implementation design](docs/stage-2-project-discovery.md)
|
|
933
|
-
- [Stage 3: Runtime Events and Streaming design](docs/stage-3-runtime-events.md)
|
|
934
|
-
- [Stage 4: Sessions and interactive mode design](docs/stage-4-sessions.md)
|
|
935
|
-
- [Stage 5: Write tools and the workspace split](docs/stage-5-write-tools.md)
|
|
936
|
-
- [Stage 6: Provider registry and credential chain](docs/stage-6-provider-registry.md)
|
|
937
|
-
- [Stage 7: Context budget and compaction](docs/stage-7-context-management.md)
|
|
938
|
-
- [Stage 8: Shell tool and streaming subprocesses](docs/stage-8-shell-tool.md)
|
|
939
|
-
- [Stage 9: Extensions and project trust](docs/stage-9-extensions.md)
|
|
940
|
-
- [Stage 10: Remote sessions](docs/stage-10-remote-sessions.md)
|
|
941
|
-
- [Stage 11: Evals](docs/stage-11-evals.md)
|
|
942
|
-
- [Stage 12: Token usage](docs/stage-12-usage.md)
|
|
943
|
-
- [Release process](docs/releasing.md)
|
|
944
|
-
|
|
945
|
-
## Contributing
|
|
946
|
-
|
|
947
|
-
Issues and focused pull requests are welcome. Before submitting a change, run:
|
|
147
|
+
## Development
|
|
948
148
|
|
|
949
149
|
```bash
|
|
950
|
-
|
|
150
|
+
git clone https://github.com/chivopic/chivgent.git
|
|
151
|
+
cd chivgent
|
|
152
|
+
npm install
|
|
951
153
|
npm test
|
|
952
|
-
npm run build
|
|
953
154
|
```
|
|
954
155
|
|
|
955
|
-
|
|
956
|
-
Agent runtime independent from vendor SDK schemas.
|
|
156
|
+
Tests use scripted model clients and do not spend API credits. Issues and focused pull requests are welcome. Keep provider-specific types in `src/providers/`, so the agent does not depend on a vendor SDK.
|
|
957
157
|
|
|
958
158
|
## License
|
|
959
159
|
|
|
960
|
-
|
|
160
|
+
[MIT](LICENSE)
|