flint-agent 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/.env.example +108 -0
  2. package/CHANGELOG.md +55 -0
  3. package/FEATURES.md +298 -0
  4. package/LICENSE +21 -0
  5. package/README.md +435 -0
  6. package/bin/flint.js +47 -0
  7. package/config/classifier-prompt.md +218 -0
  8. package/config/models-curated.json +4 -0
  9. package/config/providers.json +74 -0
  10. package/package.json +92 -0
  11. package/patches/ink+6.8.0.patch +78 -0
  12. package/profiles/desktop.md +65 -0
  13. package/profiles/generic.md +20 -0
  14. package/profiles/marketer.md +20 -0
  15. package/profiles/profiles.json +34 -0
  16. package/profiles/ux-reviewer.md +25 -0
  17. package/src/agent/agent.js +1743 -0
  18. package/src/agent/auto.js +346 -0
  19. package/src/agent/backoff.js +143 -0
  20. package/src/agent/compression.js +310 -0
  21. package/src/agent/content-resolver.js +180 -0
  22. package/src/agent/flow-controller.js +309 -0
  23. package/src/agent/intent-manifest.js +231 -0
  24. package/src/agent/intent-timeout.js +46 -0
  25. package/src/agent/intent.js +633 -0
  26. package/src/agent/knowledge.js +114 -0
  27. package/src/agent/learning.js +180 -0
  28. package/src/agent/modes.js +187 -0
  29. package/src/agent/outcome-ask.js +91 -0
  30. package/src/agent/project-context.js +76 -0
  31. package/src/agent/prompt-budget.js +117 -0
  32. package/src/agent/reflection-extractor.js +140 -0
  33. package/src/agent/steering.js +86 -0
  34. package/src/agent/supervisor.js +430 -0
  35. package/src/agent/swap.js +443 -0
  36. package/src/agent/system-prompt.js +446 -0
  37. package/src/agent/time-stamp.js +48 -0
  38. package/src/agent/tool-guard.js +201 -0
  39. package/src/agent/toolcall-text.js +162 -0
  40. package/src/agent/usage.js +297 -0
  41. package/src/agent/vision.js +94 -0
  42. package/src/agent/watchdog.js +139 -0
  43. package/src/agent/workspace-changes.js +177 -0
  44. package/src/api/address.js +14 -0
  45. package/src/api/client.js +280 -0
  46. package/src/api/server.js +535 -0
  47. package/src/api/stream-pipe.js +113 -0
  48. package/src/app-state.js +39 -0
  49. package/src/bootstrap.js +501 -0
  50. package/src/bus/drain-loop.js +497 -0
  51. package/src/bus/index.js +270 -0
  52. package/src/bus/plugins.js +65 -0
  53. package/src/child-idle.js +14 -0
  54. package/src/cli.js +118 -0
  55. package/src/commands/commands.js +1297 -0
  56. package/src/commands/registry.js +132 -0
  57. package/src/components/App.js +491 -0
  58. package/src/components/CarefulMenu.js +145 -0
  59. package/src/components/HistoryWriter.js +86 -0
  60. package/src/components/LineInput.js +69 -0
  61. package/src/components/LiveZone.js +294 -0
  62. package/src/components/OverlayMenu.js +179 -0
  63. package/src/components/SystemPanel.js +156 -0
  64. package/src/components/Table.js +54 -0
  65. package/src/config.js +249 -0
  66. package/src/free-models.js +230 -0
  67. package/src/index.js +1111 -0
  68. package/src/input-handler.js +13 -0
  69. package/src/input-text.js +123 -0
  70. package/src/launcher.js +129 -0
  71. package/src/logging/api-log.js +95 -0
  72. package/src/logging/chat-log-follower.js +113 -0
  73. package/src/logging/chat-log.js +15 -0
  74. package/src/logging/log-collector.js +182 -0
  75. package/src/logging/logger.js +112 -0
  76. package/src/logging/tool-log.js +20 -0
  77. package/src/mcp-client.js +314 -0
  78. package/src/memory/conversation-digest.js +113 -0
  79. package/src/memory/extract-facts.js +98 -0
  80. package/src/memory/facts.js +181 -0
  81. package/src/memory/inbox.js +63 -0
  82. package/src/memory/markdown.js +38 -0
  83. package/src/memory/patterns.js +185 -0
  84. package/src/memory/project.js +66 -0
  85. package/src/memory/reflections.js +74 -0
  86. package/src/memory/retrieval.js +84 -0
  87. package/src/memory/rules.js +105 -0
  88. package/src/memory/session-facts.js +125 -0
  89. package/src/memory/skills.js +191 -0
  90. package/src/memory/sqlite-store.js +653 -0
  91. package/src/memory/store.js +208 -0
  92. package/src/memory/tools.js +196 -0
  93. package/src/memory/user-model.js +86 -0
  94. package/src/message-handler.js +775 -0
  95. package/src/model-check.js +218 -0
  96. package/src/plugins/loader.js +120 -0
  97. package/src/plugins/manager.js +88 -0
  98. package/src/production-env.js +22 -0
  99. package/src/profiles.js +42 -0
  100. package/src/providers/adapters/anthropic.js +270 -0
  101. package/src/providers/adapters/openai.js +120 -0
  102. package/src/providers/keys-dpapi.js +41 -0
  103. package/src/providers/keys-fallback.js +31 -0
  104. package/src/providers/keys.js +132 -0
  105. package/src/providers/models.js +154 -0
  106. package/src/providers/registry.js +56 -0
  107. package/src/providers/state.js +56 -0
  108. package/src/registry.js +96 -0
  109. package/src/restart.js +29 -0
  110. package/src/sandbox/backend.js +130 -0
  111. package/src/security/api-auth.js +132 -0
  112. package/src/security/audit.js +98 -0
  113. package/src/security/child-policy.js +41 -0
  114. package/src/security/command-guard.js +173 -0
  115. package/src/security/content-fence.js +250 -0
  116. package/src/security/content-validator.js +132 -0
  117. package/src/security/index.js +143 -0
  118. package/src/security/network-guard.js +126 -0
  119. package/src/security/pairing.js +180 -0
  120. package/src/security/path-guard.js +140 -0
  121. package/src/security/persona-guard.js +67 -0
  122. package/src/security/policies.js +452 -0
  123. package/src/security/safety-constants.js +34 -0
  124. package/src/security/watchdog.js +107 -0
  125. package/src/sessions.js +130 -0
  126. package/src/spend.js +97 -0
  127. package/src/startup-watchdog.js +59 -0
  128. package/src/stdio/args.js +71 -0
  129. package/src/stdio/guard.js +59 -0
  130. package/src/stdio/protocol.js +167 -0
  131. package/src/stdio/run.js +106 -0
  132. package/src/stdio/session.js +180 -0
  133. package/src/store/agent-slice.js +306 -0
  134. package/src/store/dataset-slice.js +73 -0
  135. package/src/store/index.js +22 -0
  136. package/src/store/process-slice.js +135 -0
  137. package/src/store/session-slice.js +191 -0
  138. package/src/store/ui-slice.js +119 -0
  139. package/src/tasks/db.js +184 -0
  140. package/src/tasks/queries.js +589 -0
  141. package/src/tools/agent-tools.js +473 -0
  142. package/src/tools/checkpoint.js +152 -0
  143. package/src/tools/command-approvals.js +180 -0
  144. package/src/tools/dataset.js +50 -0
  145. package/src/tools/filesystem.js +682 -0
  146. package/src/tools/inbox-tools.js +48 -0
  147. package/src/tools/mesh.js +135 -0
  148. package/src/tools/own-env.js +136 -0
  149. package/src/tools/permissions.js +681 -0
  150. package/src/tools/plugin-tools.js +123 -0
  151. package/src/tools/process-tools.js +595 -0
  152. package/src/tools/registry.js +307 -0
  153. package/src/tools/swap-tools.js +72 -0
  154. package/src/tools/system.js +662 -0
  155. package/src/tools/tasks.js +532 -0
  156. package/src/tools/tool-search.js +171 -0
  157. package/src/ui/header.js +140 -0
  158. package/src/ui/input-cursor.js +23 -0
  159. package/src/ui/last-line.js +25 -0
  160. package/src/ui/line-edit.js +135 -0
  161. package/src/ui/output.js +399 -0
  162. package/src/ui/paste-tokens.js +131 -0
  163. package/src/ui/prompt-attention.js +134 -0
  164. package/src/ui/render-options.js +13 -0
  165. package/src/ui/replay.js +94 -0
  166. package/src/ui/splash.js +49 -0
  167. package/src/ui/status-level.js +36 -0
  168. package/src/ui/tool-ledger.js +203 -0
  169. package/src/ui/window-title.js +150 -0
  170. package/src/update.js +205 -0
  171. package/system.md +63 -0
package/README.md ADDED
@@ -0,0 +1,435 @@
1
+ <picture>
2
+ <source media="(prefers-color-scheme: dark)" srcset="assets/flint-mark-dark.svg">
3
+ <img alt="Flint" src="assets/flint-mark-light.svg" width="270">
4
+ </picture>
5
+
6
+ # Flint Agent
7
+
8
+ [![CI](https://github.com/dklymentiev/flint-agent/actions/workflows/ci.yml/badge.svg)](https://github.com/dklymentiev/flint-agent/actions/workflows/ci.yml)
9
+ [![npm](https://img.shields.io/npm/v/flint-agent)](https://www.npmjs.com/package/flint-agent)
10
+ [![Node](https://img.shields.io/node/v/flint-agent)](https://nodejs.org)
11
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
12
+
13
+ **A lightweight AI agent for your terminal, built to work well with any
14
+ model, cheap and free ones included.** It reads files, writes code, runs
15
+ commands, searches the web, uses MCP servers and remembers what you taught
16
+ it. On OpenRouter's free tier, `/model free` picks the free models that can
17
+ call tools and falls back to another when one is busy.
18
+
19
+ It works with OpenRouter, OpenAI, Anthropic, Google, Groq, Together or a
20
+ local Ollama, and installs as a single npm package: no Python, no Docker, no
21
+ background service.
22
+
23
+ Project page: https://klymentiev.com/projects/flint
24
+
25
+ ---
26
+
27
+ ## What it does
28
+
29
+ Ask Flint the way you would ask a colleague:
30
+
31
+ ```
32
+ > Read my project and tell me what it does
33
+ > Find all TODO comments and make a plan to fix them
34
+ > Write a Python script that converts CSV to JSON, then run it
35
+ > Take a screenshot of the desktop and click on Chrome
36
+ > Search the web for React best practices in 2026
37
+ > Remember that our deploy day is Wednesday
38
+ ```
39
+
40
+ Flint picks the tools, asks before anything risky (by default: deleting a
41
+ file, destructive or one-way commands such as `git push`, child agents and
42
+ MCP tools), and shows each tool call as it happens.
43
+
44
+ ---
45
+
46
+ ## Install
47
+
48
+ Needs Node.js 22.12 or newer.
49
+
50
+ ```bash
51
+ npm install -g flint-agent
52
+ flint
53
+ ```
54
+
55
+ Or from the repository:
56
+
57
+ ```bash
58
+ git clone https://github.com/dklymentiev/flint-agent.git
59
+ cd flint-agent
60
+ npm install
61
+ npm link # makes the `flint` command point at this folder
62
+ flint
63
+ ```
64
+
65
+ On the first run a short setup picks a provider, takes your API key and asks
66
+ how careful Flint should be. `flint --version` checks the install.
67
+
68
+ **`flint` not found on Windows?** npm puts its commands in the folder that
69
+ `npm prefix -g` prints (usually `%APPDATA%\npm`), and that folder has to be on
70
+ your PATH. Add it under Settings, System, About, Advanced system settings,
71
+ Environment Variables, then open a new terminal. `npm start` in the Flint
72
+ folder works either way.
73
+
74
+ **Updates.** Flint says when a newer version is out, at most once a day, and
75
+ `/update` installs it and restarts in the same session. It never updates on
76
+ its own, and it refuses to overwrite local changes. See
77
+ [docs/self-update.md](docs/self-update.md).
78
+
79
+ ### Command line
80
+
81
+ ```bash
82
+ flint # start a new session
83
+ flint --last # continue the last session
84
+ flint --model google/gemini-2.5-flash # pick a model
85
+ flint --provider anthropic # use Anthropic directly
86
+ flint --profile desktop # desktop automation profile
87
+ flint --headless --task "Fix the bug" --cwd ./my-project
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Free OpenRouter models: run Flint on the free tier
93
+
94
+ Flint runs on [OpenRouter](https://openrouter.ai)'s free tier: free models
95
+ from several vendors behind one API key, through OpenRouter's free LLM API.
96
+
97
+ 1. Create a free key at openrouter.ai.
98
+ 2. Run `flint` and paste the key when it asks.
99
+ 3. Type `/model free auto`.
100
+
101
+ Most free models cannot call tools, and the ones that can are often
102
+ rate-limited. Flint keeps only the free models that can call tools (the
103
+ `:free` variants and the other zero-priced ones), ranks them by current speed
104
+ and uptime from OpenRouter's public stats, and hands OpenRouter the best one
105
+ with two fallbacks from other vendors, so a busy model passes the request to
106
+ the next. Flint counts today's free requests in the footer. `/model free`
107
+ shows the list; `/model test` scores any model on small agent tasks. More in
108
+ [docs/free-mode.md](docs/free-mode.md).
109
+
110
+ ### Can I use Flint for free?
111
+
112
+ Yes. Create a free OpenRouter key, paste it when Flint asks, then run
113
+ `/model free auto`. Flint itself is free and open source (MIT).
114
+
115
+ ### Which free OpenRouter models work with Flint?
116
+
117
+ The free models that can call tools, because an agent works through tools.
118
+ Flint reads that from OpenRouter's model list and ranks them live by speed and
119
+ uptime, so the choice follows OpenRouter as its free list changes.
120
+
121
+ ### How does `/model free auto` pick a model?
122
+
123
+ It ranks the free tool-calling models by current throughput and uptime,
124
+ takes the best, and sets two fallbacks from other vendors. When the first is
125
+ rate-limited or down, OpenRouter passes the request to the next.
126
+
127
+ ---
128
+
129
+ ## How it works
130
+
131
+ You type a message. Flint sends it to the model with a set of tools. The
132
+ model decides which tools to call, Flint runs them (asking first when the
133
+ action is risky) and loops until the task is done.
134
+
135
+ The conversation is ordinary terminal output: scroll and select it with your
136
+ terminal. Only a few rows at the bottom are live: what Flint is doing, the
137
+ background processes it started, the input line and one status line. Each
138
+ tool call leaves one line, and each turn ends with a receipt: tools used,
139
+ files changed, tokens in and out, time and cost.
140
+
141
+ **Esc** stops the running turn; pressed again, it stops background processes,
142
+ newest first. **Ctrl+C** twice exits. **Up/Down** recalls earlier input.
143
+
144
+ ---
145
+
146
+ ## Features
147
+
148
+ ### Any model, including free ones
149
+
150
+ | Provider | Default model |
151
+ |---|---|
152
+ | [OpenRouter](https://openrouter.ai) (default) | google/gemini-2.5-flash |
153
+ | OpenAI | gpt-4o |
154
+ | Anthropic | claude-sonnet-4-6 |
155
+ | Google Gemini (OpenAI-compatible endpoint) | gemini-3-flash-preview |
156
+ | Groq | llama-3.3-70b-versatile |
157
+ | Together | meta-llama/Llama-3.3-70B-Instruct-Turbo |
158
+ | Ollama (local) | llama3.2 |
159
+
160
+ Switch with `/provider` and `/model`, also in the middle of a conversation.
161
+ Providers are defined in `config/providers.json`; your own copy in
162
+ `~/.flint/providers.json` adds or overrides them. API keys are stored
163
+ encrypted (DPAPI on Windows, AES-256-GCM elsewhere).
164
+
165
+ **Free models.** See [Free OpenRouter models](#free-openrouter-models-run-flint-on-the-free-tier)
166
+ above. `/model test` runs small agent tasks with checked answers on any model
167
+ and saves the score: [docs/model-check.md](docs/model-check.md).
168
+
169
+ ### Tools, and more through MCP
170
+
171
+ Built-in tools cover files (read, write, edit, search, with checkpoints and
172
+ undo), shell commands and background processes, the web (fetch a page,
173
+ search), persistent memory, task plans, child agents, and desktop control
174
+ through an MCP desktop server.
175
+
176
+ Any [MCP](https://modelcontextprotocol.io) server adds its tools: mail,
177
+ chat, databases, your own APIs. Configure servers in `MCP_SERVERS` or in a
178
+ `.mcp.json` file in the working folder:
179
+
180
+ ```env
181
+ MCP_SERVERS=gmail|http|http://localhost:9090/mcp,my-db|stdio|~/my-db-server mcp
182
+ ```
183
+
184
+ With many MCP tools, Flint lists them by name in a `tool_search` tool and
185
+ loads the ones the model asks for, so they do not fill every request.
186
+
187
+ ### Long sessions that stay affordable
188
+
189
+ Every call to the model sends the whole conversation again. Flint keeps that
190
+ down in three ways:
191
+
192
+ - **Tool search**, above.
193
+ - **Swap.** Big and old tool results, and old turns of a long conversation,
194
+ move to the session's folder on disk. One line stays in their place
195
+ (`[swap #37 · page · <url> · 11 KB · "<title>" · turn 12 · swap_read 37]`),
196
+ and the agent reads them back with `swap_read` when it needs them. Nothing
197
+ is lost. See [docs/context-swap.md](docs/context-swap.md).
198
+ - **Compression.** The last resort: old tool results are cut to a one-line
199
+ summary. This one does lose text.
200
+
201
+ One switch decides how early they start:
202
+
203
+ | | economy | normal (default) | generous |
204
+ |---|---|---|---|
205
+ | For | paid models, long sessions | most work | capable models with big windows, quality first |
206
+ | MCP tools offered whole | up to 10 | up to 30 | up to 200 |
207
+ | Swap wakes up at | ~16k-32k tokens of context | ~48k-96k | near the window's edge |
208
+ | Compression starts at | a quarter of the window (max 64k) | half the window (max 128k) | 80% of the window |
209
+ | Old conversation goes to swap at | 40% of the window (max 150k) | 60% (max 300k) | 85% |
210
+ | Big result goes to swap when awake | over 2 KB | over 4 KB | over 16 KB |
211
+ | Token-saving advice to the model | yes | no | no |
212
+
213
+ Below those thresholds nothing is moved or shortened. `/spend` shows the
214
+ modes; `/spend economy`, `/spend normal`, `/spend generous` (or `e`, `n`, `g`)
215
+ switch and are remembered; `FLINT_SPEND` in the environment wins. Money
216
+ limits are separate: `AGENT_MAX_COST` per message and `AGENT_SESSION_BUDGET`
217
+ per session, both unlimited by default. See [docs/spend-modes.md](docs/spend-modes.md).
218
+
219
+ ### Sessions
220
+
221
+ Sessions are saved as you go. `/resume` picks a recent one to continue,
222
+ `/new` starts a fresh one, and restarts (`/restart`, `/update`) keep the
223
+ session you were in.
224
+
225
+ ### Autonomous mode
226
+
227
+ ```
228
+ > /auto Refactor the auth module to use JWT, update all tests, write migration docs
229
+ ```
230
+
231
+ Flint writes a plan, works through it task by task, keeps progress in SQLite
232
+ (`/plan`, `/tasks`), and stops when it is done or when it reaches your
233
+ budget. `/continue` resumes unfinished work.
234
+
235
+ ### Persistent memory
236
+
237
+ ```
238
+ > Remember that our API rate limit is 5000 req/min
239
+ > What's our rate limit?
240
+ ```
241
+
242
+ Memory survives across sessions and is protected by an HMAC integrity
243
+ check: a memory file changed outside Flint is detected and not loaded.
244
+
245
+ ### Profiles
246
+
247
+ | Profile | For | Context |
248
+ |---|---|---|
249
+ | `generic` (default) | coding, files, general tasks | full history, compressed when it grows |
250
+ | `desktop` | GUI automation, browser | last 15 messages |
251
+ | `marketer` | content, research, analysis | last 15 messages |
252
+ | `ux-reviewer` | UI and UX reviews | full history |
253
+
254
+ `/profile <name>` switches. Add your own: a markdown file in `profiles/` and
255
+ an entry in `profiles/profiles.json`.
256
+
257
+ ### Plugins
258
+
259
+ ```
260
+ /install <git url or path>
261
+ /plugins
262
+ /uninstall <name>
263
+ ```
264
+
265
+ A plugin can add tools, hooks and commands.
266
+
267
+ ---
268
+
269
+ ## Safety
270
+
271
+ Flint runs commands and edits files on your machine, so it asks first. On the
272
+ first run you choose how often (`/careful` changes it later):
273
+
274
+ - **safe**: asks before every change to files and every command;
275
+ - **normal** (default): edits files and runs ordinary commands, but asks
276
+ before deleting a file, destructive commands (`rm -r`, `git reset --hard`),
277
+ one-way ones (pushing to git, publishing, uploads, mail), child agents and
278
+ MCP tools;
279
+ - **permissive**: asks only before deleting a file and reconnecting an MCP
280
+ server.
281
+
282
+ Reading a secret file (`.env`, SSH keys, credentials) asks at every level,
283
+ and some commands are refused at every level. Around that sit further guards:
284
+ filesystem paths can be limited (`AGENT_ALLOWED_PATHS`), requests to internal
285
+ network addresses are refused, outside content is screened for prompt
286
+ injection, child agents inherit the blocked paths and cannot nest deeper than
287
+ five levels, and every tool call goes to an audit log.
288
+ `/permissions`, `/allow <tool>`, `/deny <tool>` and `/confirm <tool>` set
289
+ single tools; `/allow-all` skips confirmations for the session.
290
+
291
+ These guards reduce risk; they do not make running an AI agent with your
292
+ permissions safe in every case. Read what it asks before you answer. See
293
+ [SECURITY.md](SECURITY.md) to report a problem.
294
+
295
+ ---
296
+
297
+ ## Running Flint from other programs
298
+
299
+ ### Headless
300
+
301
+ ```bash
302
+ flint --headless --task "Fix the failing test in auth.test.js" --cwd ./project --budget 0.50
303
+ ```
304
+
305
+ Runs one task and prints JSON on stdout:
306
+
307
+ ```json
308
+ {"response": "Fixed the test...", "cost": 0.034, "tokens": 12500}
309
+ ```
310
+
311
+ ### Stdio (stream-json subprocess)
312
+
313
+ A host that drives an agent CLI as a long-lived subprocess can drive Flint the
314
+ same way, with the same flags and the same JSON lines:
315
+
316
+ ```bash
317
+ flint --print --verbose --model stealth/space-bunny-alpha \
318
+ --input-format stream-json --output-format stream-json \
319
+ --session-id 0b7c4c8e-1f2a-4d3b-9c8d-1234567890ab
320
+ ```
321
+
322
+ Write `{"type":"user","message":{"role":"user","content":"..."}}` lines to
323
+ stdin; read `system`, `assistant`, `user` (tool results) and `result` lines
324
+ from stdout. The working folder's `CLAUDE.md` files and `.mcp.json` are read.
325
+ See [docs/stdio-mode.md](docs/stdio-mode.md).
326
+
327
+ ### HTTP API
328
+
329
+ A running Flint listens on `127.0.0.1:3000`. A program pairs once (you confirm
330
+ a PIN in the console) and then sends messages, reads status and history,
331
+ manages the queue and stops tasks:
332
+
333
+ ```bash
334
+ curl -X POST 127.0.0.1:3000/pair/request -d '{"agentName":"my-script"}'
335
+ # Flint shows a PIN; the program sends it to /pair/confirm and gets a token,
336
+ # once: it stays valid across restarts until /paired revoke my-script.
337
+ curl -X POST 127.0.0.1:3000/message \
338
+ -H "Authorization: Bearer <token>" \
339
+ -d '{"content":"What files changed today?"}'
340
+ ```
341
+
342
+ ---
343
+
344
+ ## Commands
345
+
346
+ | Command | What it does |
347
+ |---|---|
348
+ | `/help` | all commands and keys |
349
+ | `/model [id]`, `/model free`, `/model test` | show or switch the model; free models; score a model |
350
+ | `/provider [name]`, `/key` | switch provider; manage API keys |
351
+ | `/resume`, `/new`, `/sessions`, `/load <id>` | sessions |
352
+ | `/spend [level]` | economy, normal or generous |
353
+ | `/careful` | how often Flint asks: safe, normal, permissive |
354
+ | `/auto <task>`, `/continue`, `/plan`, `/tasks` | autonomous work and its plan |
355
+ | `/rewind [N or all]` | undo file changes made in this session |
356
+ | `/tools [n]`, `/sys`, `/budget` | recent tool calls; model, cost and context; spending |
357
+ | `/ps`, `/logs <id>`, `/kill <id>` | background processes |
358
+ | `/mcp`, `/plugins` | MCP servers, plugins |
359
+ | `/memory` | memory stats (`/memory clear` empties it) |
360
+ | `/update`, `/restart` | install a newer version; restart, same session |
361
+ | `exit` | save and quit |
362
+
363
+ ### Keys
364
+
365
+ | Key | Action |
366
+ |---|---|
367
+ | `Esc` | clear the input; stop the turn; then stop background processes, newest first |
368
+ | `Ctrl+C` | stop the turn; twice within 2 s exits |
369
+ | `Up` / `Down` | input history |
370
+ | `Alt+V` | paste a picture (or text) from the clipboard as `[Image #N]` |
371
+ | `Ctrl+U`, `Ctrl+W` | clear the line, delete a word |
372
+
373
+ `Ctrl+V` is the terminal's own paste: text works, but with a picture in the
374
+ clipboard most terminals send nothing, so use `Alt+V`.
375
+
376
+ ---
377
+
378
+ ## Configuration
379
+
380
+ Everything is set in a `.env` file or environment variables; see
381
+ [`.env.example`](.env.example) for the full list with descriptions. The ones
382
+ most people touch:
383
+
384
+ | Variable | Default | What it does |
385
+ |---|---|---|
386
+ | `OPENROUTER_API_KEY` | none | key for OpenRouter (the setup can store it instead) |
387
+ | `OPENROUTER_MODEL` | provider's default | model to start with |
388
+ | `AGENT_MAX_ITERATIONS` | 150 | tool-call steps per message |
389
+ | `AGENT_MAX_COST` | 0 (no limit) | cost limit per message, in dollars |
390
+ | `AGENT_ALLOWED_PATHS` | none | folders the file tools may touch |
391
+ | `MCP_SERVERS` | none | external tool servers |
392
+ | `INTENT_MODEL` | none | optional model that picks the tools for each message; unset offers them all |
393
+ | `FLINT_SPEND` | saved choice | economy, normal or generous |
394
+ | `FLINT_UPDATE_CHECK` | 1 | 0 turns off the daily update check |
395
+
396
+ ---
397
+
398
+ ## Documentation
399
+
400
+ - [docs/guide.md](docs/guide.md): user guide
401
+ - [docs/technical-reference.md](docs/technical-reference.md): modules, tools and settings in detail
402
+ - [docs/providers.md](docs/providers.md): providers and keys
403
+ - [docs/console-spec.md](docs/console-spec.md): the console
404
+ - [docs/stdio-mode.md](docs/stdio-mode.md), [docs/context-swap.md](docs/context-swap.md),
405
+ [docs/spend-modes.md](docs/spend-modes.md), [docs/free-mode.md](docs/free-mode.md),
406
+ [docs/model-check.md](docs/model-check.md), [docs/self-update.md](docs/self-update.md)
407
+ - [FEATURES.md](FEATURES.md): feature list
408
+ - [CHANGELOG.md](CHANGELOG.md): what changed in each version
409
+
410
+ ---
411
+
412
+ ## Development
413
+
414
+ ```bash
415
+ git clone https://github.com/dklymentiev/flint-agent.git
416
+ cd flint-agent
417
+ npm install
418
+ npm test
419
+ ```
420
+
421
+ Flint and its tests need Node.js 22.12 or newer. No `.env` and no API key
422
+ are needed: the tests stub the model.
423
+
424
+ Stack: Node.js (ESM), React 19 and Ink 6 for the terminal UI, Zustand for
425
+ state, SQLite for the message queue, tasks and memory index.
426
+
427
+ See [CONTRIBUTING.md](CONTRIBUTING.md) before sending a change.
428
+
429
+ If Flint is useful to you, a star on GitHub helps other people find it.
430
+
431
+ ---
432
+
433
+ ## License
434
+
435
+ [MIT](LICENSE)
package/bin/flint.js ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Flint CLI entry point
4
+ // Delegates to launcher.js (which handles auto-restart on exit code 42).
5
+ // Plain Node, no loader: the source has no JSX (components call
6
+ // createElement). The esbuild loader this used to start with was a dev
7
+ // dependency, so `npm install -g` left `flint` unable to start.
8
+
9
+ import { fileURLToPath } from "node:url";
10
+ import { dirname, join } from "node:path";
11
+ import { spawn } from "node:child_process";
12
+
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const launcher = join(__dirname, "..", "src", "launcher.js");
15
+
16
+ // `flint --version`: the quickest check that the command works after an
17
+ // install, without starting anything.
18
+ if (process.argv.includes("--version") || process.argv.includes("-v")) {
19
+ const { readFileSync } = await import("node:fs");
20
+ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf8"));
21
+ console.log(`flint ${pkg.version}`);
22
+ process.exit(0);
23
+ }
24
+
25
+ // The stdio mode runs in this process: no launcher, no splash, no restart.
26
+ // A host may pass files as inherited descriptors (--system-prompt-file
27
+ // /proc/self/fd/N), and a child process does not get
28
+ // them: through bin, launcher and index.js the path named some other
29
+ // descriptor of the grandchild, and reading it hung the start (Linux,
30
+ // 2026-10-02). One process is also the one the host signals.
31
+ const userArgs = process.argv.slice(2);
32
+ const stdioMode = userArgs.includes("--stdio") || userArgs.some((a, i) =>
33
+ (a === "--input-format" || a === "--output-format") && userArgs[i + 1] === "stream-json");
34
+ if (stdioMode) {
35
+ await import(new URL("../src/index.js", import.meta.url));
36
+ } else {
37
+
38
+ const child = spawn(process.execPath, [
39
+ launcher,
40
+ ...userArgs,
41
+ ], {
42
+ stdio: "inherit",
43
+ cwd: process.cwd(),
44
+ });
45
+
46
+ child.on("exit", (code) => process.exit(code ?? 1));
47
+ }