@nomad-e/bluma-cli 0.1.41 → 0.1.43
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 +545 -1057
- package/dist/config/native_tools.json +53 -12
- package/dist/main.js +4058 -2671
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -1,1216 +1,704 @@
|
|
|
1
|
-
# BluMa — Base Language Unit · Model Agent
|
|
1
|
+
# BluMa CLI — Base Language Unit · Model Agent
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/bluma)
|
|
3
|
+
[](https://www.npmjs.com/package/@nomad-e/bluma-cli)
|
|
4
4
|
[](LICENSE)
|
|
5
|
-
[](https://nodejs.org/)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
<img src="https://pharmaseedevsa.blob.core.windows.net/pharmassee-dev-storage/bluma.png" alt="Screenshot BluMa CLI" width="1000"/>
|
|
9
|
-
</p>
|
|
10
|
-
|
|
11
|
-
BluMa is a CLI-based model agent responsible for language-level code generation, refactoring and semantic transformations in the Factor AI stack. The project is a conversational assistant that interacts via terminal (CLI), built with React/Ink, supporting smart agents (LLM via FactorRouter), tool execution, persistent history, session management, coding memory, and extensibility through external plugins/tools and skills.
|
|
7
|
+
**BluMa** is a CLI-based model agent for advanced software engineering workflows. Built with React/Ink 5, it provides an interactive terminal interface for LLM-powered automation, code generation, refactoring, and task execution. Features persistent sessions, contextual reasoning, smart feedback, and extensible tools/skills architecture.
|
|
12
8
|
|
|
13
9
|
---
|
|
14
10
|
|
|
15
11
|
## Table of Contents
|
|
12
|
+
|
|
16
13
|
- [Overview](#overview)
|
|
17
|
-
- [Why BluMa?](#why-bluma)
|
|
18
14
|
- [Key Features](#key-features)
|
|
19
15
|
- [Requirements](#requirements)
|
|
20
|
-
- [Quick Start](#quick-start)
|
|
21
16
|
- [Installation](#installation)
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
24
|
-
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
- [
|
|
28
|
-
- [
|
|
29
|
-
- [
|
|
30
|
-
- [
|
|
31
|
-
- [
|
|
32
|
-
- [Security Notes](#-security-notes)
|
|
33
|
-
- [Tech Stack Overview](#stack)
|
|
34
|
-
- [Contributing](#-contributing)
|
|
17
|
+
- [Quick Start](#quick-start)
|
|
18
|
+
- [Configuration](#configuration)
|
|
19
|
+
- [Architecture](#architecture)
|
|
20
|
+
- [Native Tools](#native-tools)
|
|
21
|
+
- [Skills System](#skills-system)
|
|
22
|
+
- [Runtime & Orchestration](#runtime--orchestration)
|
|
23
|
+
- [Slash Commands](#slash-commands)
|
|
24
|
+
- [Development](#development)
|
|
25
|
+
- [Testing](#testing)
|
|
26
|
+
- [Contributing](#contributing)
|
|
35
27
|
- [License](#license)
|
|
36
28
|
|
|
37
29
|
---
|
|
38
30
|
|
|
39
|
-
##
|
|
40
|
-
|
|
31
|
+
## Overview
|
|
32
|
+
|
|
33
|
+
BluMa operates as a **conversational agent** in the terminal, combining:
|
|
34
|
+
|
|
35
|
+
- **Rich UI Layer**: React/Ink 5 components for interactive prompts, live overlays, and real-time feedback
|
|
36
|
+
- **Agent Layer**: LLM orchestration via FactorRouter with tool invocation and context management
|
|
37
|
+
- **Runtime Layer**: Task tracking, plugin system, hooks, diagnostics, and session management
|
|
38
|
+
- **Tool Layer**: 18 native tools + MCP SDK integration for external tools
|
|
39
|
+
|
|
40
|
+
The agent maintains persistent conversation history, workspace snapshots, and coding memory across sessions.
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
##
|
|
45
|
-
BluMa stands out as the premier CLI-based model agent for software engineering:
|
|
44
|
+
## Key Features
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
- **
|
|
49
|
-
- **
|
|
50
|
-
- **
|
|
51
|
-
- **
|
|
46
|
+
### Core Agent
|
|
47
|
+
- **Interactive CLI**: Rich terminal UI with React/Ink 5
|
|
48
|
+
- **Session Persistence**: Automatic save/load of conversation and tool history
|
|
49
|
+
- **Context Management**: Token-aware context compression with history anchoring
|
|
50
|
+
- **Smart Feedback**: Technical suggestions and automated checks
|
|
51
|
+
- **Confirmation System**: Controlled execution with whitelists and previews
|
|
52
|
+
- **Coding Memory**: Persistent notes about codebase decisions (`~/.bluma/coding_memory.json`)
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
### Runtime & Orchestration (v0.1.41+)
|
|
55
|
+
- **Plugin System**: Load plugins from `.bluma/plugins/` or `~/.bluma/plugins/`
|
|
56
|
+
- **Hook Registry**: Event-driven lifecycle tracking (tool calls, decisions, state changes)
|
|
57
|
+
- **Task Store**: Persistent task management with PLANNING → EXECUTION → VERIFICATION flow
|
|
58
|
+
- **Session Registry**: Multi-session support with process health monitoring
|
|
59
|
+
- **Diagnostics**: Real-time system snapshot (tasks, hooks, plugins, sessions)
|
|
60
|
+
- **Tool Execution Policy**: Intelligent decisions based on sandbox mode and safety
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
### Tools & Skills
|
|
63
|
+
- **25+ Native Tools**: File operations, search, shell commands, web fetch, agent coordination
|
|
64
|
+
- **MCP Integration**: Model Context Protocol SDK for external tool servers
|
|
65
|
+
- **Skills System**: Pluggable knowledge modules (git, PDF, Excel, etc.)
|
|
66
|
+
- **Agent Coordination**: Spawn/wait/list subagents for parallel work
|
|
56
67
|
|
|
57
|
-
|
|
58
|
-
- **
|
|
59
|
-
- **
|
|
60
|
-
- **
|
|
61
|
-
- **Tool
|
|
62
|
-
- **
|
|
63
|
-
- **Smart feedback component** with technical suggestions and checks.
|
|
64
|
-
- **ConfirmPrompt & Workflow Decision:** confirmations for sensitive operations, edit/code previews, always-accepted tool whitelists.
|
|
65
|
-
- **Coding Memory:** persistent notes about the codebase, decisions, and context that survive across sessions.
|
|
66
|
-
- **Skills System:** pluggable knowledge modules for domain-specific expertise (git, testing, docker, etc.).
|
|
67
|
-
- **Extensible:** easily add new tools, skills, or integrate external SDK/plugins.
|
|
68
|
+
### UI Components
|
|
69
|
+
- **Slash Commands**: 20+ built-in commands (`/help`, `/model`, `/tasks`, `/plugins`, etc.)
|
|
70
|
+
- **Live Overlays**: Working timers, progress indicators, streaming text
|
|
71
|
+
- **Diff Previews**: Side-by-side code comparisons before edits
|
|
72
|
+
- **Tool Result Cards**: Structured display of tool outputs
|
|
73
|
+
- **Session Panels**: Real-time monitoring with log streaming
|
|
68
74
|
|
|
69
75
|
---
|
|
70
76
|
|
|
71
|
-
##
|
|
72
|
-
- Node.js >= 18
|
|
73
|
-
- npm >= 9
|
|
74
|
-
- FactorRouter API key (get one from your FactorRouter admin)
|
|
77
|
+
## Requirements
|
|
75
78
|
|
|
76
|
-
|
|
79
|
+
- **Node.js**: >= 20
|
|
80
|
+
- **npm**: >= 9
|
|
81
|
+
- **FactorRouter**: API key and URL for LLM backend
|
|
77
82
|
|
|
78
|
-
|
|
83
|
+
---
|
|
79
84
|
|
|
80
|
-
|
|
85
|
+
## Installation
|
|
81
86
|
|
|
82
|
-
|
|
87
|
+
### Global Installation (Recommended)
|
|
83
88
|
|
|
84
89
|
```bash
|
|
85
90
|
npm install -g @nomad-e/bluma-cli
|
|
86
91
|
```
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
sudo npm install -g @nomad-e/bluma-cli
|
|
92
|
-
```
|
|
93
|
-
- **Windows:** Open Command Prompt/Terminal as Administrator and repeat the command
|
|
94
|
-
|
|
95
|
-
> **macOS:** After global installation, **always run the `bluma` command without sudo**:
|
|
96
|
-
>
|
|
97
|
-
> ```bash
|
|
98
|
-
> bluma
|
|
99
|
-
> ```
|
|
100
|
-
> Running with sudo may cause permission problems, environment variable issues, and npm cache ownership problems.
|
|
101
|
-
> Only use sudo to install, never to run the CLI.
|
|
102
|
-
|
|
103
|
-
### Setting Up Environment Variables
|
|
104
|
-
For BluMa CLI to operate, set the following environment variables globally in your system.
|
|
105
|
-
|
|
106
|
-
**Required:**
|
|
107
|
-
- `FACTOR_ROUTER_KEY` — API key from your FactorRouter admin (e.g., `sk-fai-...`)
|
|
108
|
-
- `FACTOR_ROUTER_URL` — FactorRouter gateway base URL (e.g., `http://host:8003/router-api`)
|
|
109
|
-
|
|
110
|
-
#### How to set environment variables globally:
|
|
111
|
-
|
|
112
|
-
**Linux/macOS:**
|
|
113
|
-
Add to your `~/.bashrc`, `~/.zshrc`, or equivalent:
|
|
114
|
-
```sh
|
|
115
|
-
export FACTOR_ROUTER_KEY="your_factor_router_key"
|
|
116
|
-
export FACTOR_ROUTER_URL="http://host:8003/router-api"
|
|
117
|
-
```
|
|
118
|
-
Then run:
|
|
119
|
-
```sh
|
|
120
|
-
source ~/.bashrc # or whichever file you edited
|
|
93
|
+
**Linux/macOS** (if permission errors):
|
|
94
|
+
```bash
|
|
95
|
+
sudo npm install -g @nomad-e/bluma-cli
|
|
121
96
|
```
|
|
122
97
|
|
|
123
|
-
**
|
|
124
|
-
```cmd
|
|
125
|
-
setx FACTOR_ROUTER_KEY "your_factor_router_key"
|
|
126
|
-
setx FACTOR_ROUTER_URL "http://host:8003/router-api"
|
|
127
|
-
```
|
|
128
|
-
(Only needs to be run once per variable. Restart the terminal after.)
|
|
98
|
+
> **macOS Note**: After installation, run `bluma` **without** sudo to avoid permission issues.
|
|
129
99
|
|
|
130
|
-
|
|
131
|
-
```powershell
|
|
132
|
-
[Environment]::SetEnvironmentVariable("FACTOR_ROUTER_KEY", "your_factor_router_key", "Machine")
|
|
133
|
-
[Environment]::SetEnvironmentVariable("FACTOR_ROUTER_URL", "http://host:8003/router-api", "Machine")
|
|
134
|
-
```
|
|
100
|
+
### Local Development
|
|
135
101
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
102
|
+
```bash
|
|
103
|
+
git clone <repository-url>
|
|
104
|
+
cd bluma-cli
|
|
105
|
+
npm install
|
|
106
|
+
npm run build
|
|
141
107
|
```
|
|
142
|
-
👉 **Choose `Y` (Yes) or `A` (Yes to All)**. This will change the execution policy to **RemoteSigned** (only scripts from the internet need a digital signature).
|
|
143
108
|
|
|
144
|
-
|
|
145
|
-
- Read more: [About Execution Policies (Microsoft Docs)](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/about/about_execution_policies)
|
|
109
|
+
### Environment Setup
|
|
146
110
|
|
|
147
|
-
|
|
148
|
-
```powershell
|
|
149
|
-
Set-ExecutionPolicy Default
|
|
150
|
-
```
|
|
111
|
+
Set these environment variables globally:
|
|
151
112
|
|
|
152
|
-
|
|
113
|
+
```bash
|
|
114
|
+
# Linux/macOS: Add to ~/.bashrc, ~/.zshrc, or ~/.bash_profile
|
|
115
|
+
export FACTOR_ROUTER_KEY="sk-fai-your-key-here"
|
|
116
|
+
export FACTOR_ROUTER_URL="http://host:8003/router-api"
|
|
153
117
|
|
|
154
|
-
|
|
118
|
+
# Then reload
|
|
119
|
+
source ~/.bashrc # or ~/.zshrc
|
|
120
|
+
```
|
|
155
121
|
|
|
156
|
-
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
npx bluma
|
|
122
|
+
**Windows (PowerShell)**:
|
|
123
|
+
```powershell
|
|
124
|
+
[Environment]::SetEnvironmentVariable("FACTOR_ROUTER_KEY", "sk-fai-your-key-here", "User")
|
|
125
|
+
[Environment]::SetEnvironmentVariable("FACTOR_ROUTER_URL", "http://host:8003/router-api", "User")
|
|
161
126
|
```
|
|
162
|
-
==> The CLI will open an interactive terminal interface for dialogue, command execution, and engineering workflow automation.
|
|
163
127
|
|
|
164
128
|
---
|
|
165
129
|
|
|
166
130
|
## Quick Start
|
|
167
131
|
|
|
168
|
-
Get up and running with BluMa in minutes:
|
|
169
|
-
|
|
170
|
-
1. **Install BluMa:**
|
|
171
|
-
```bash
|
|
172
|
-
npm install -g @nomad-e/bluma-cli
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
2. **Configure Environment:**
|
|
176
|
-
Set your FactorRouter API key and URL (see [Configuration](#configuration-and-environment-variables)).
|
|
177
|
-
|
|
178
|
-
3. **Launch BluMa:**
|
|
179
|
-
```bash
|
|
180
|
-
bluma
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
4. **Interact:**
|
|
184
|
-
Start a conversation! Try commands like "Help me refactor this code" or "Run tests for my project."
|
|
185
|
-
|
|
186
|
-
For full installation details, see [Installation](#installation).
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
## <a name="sandbox-agent-mode"></a>Sandbox / Agent Mode
|
|
191
|
-
|
|
192
|
-
BluMa was designed primarily as an **interactive CLI agent**, but it also exposes a **non-interactive “agent mode”** for integration with orchestrators such as AGIWeb Sandbox or other backends.
|
|
193
|
-
|
|
194
|
-
### Why Agent Mode Exists
|
|
195
|
-
|
|
196
|
-
- Allow external systems (e.g. a Sandbox API, another agent like Severino, CI pipelines) to:
|
|
197
|
-
- Send a **single JSON payload** describing a task (`action` + `context`).
|
|
198
|
-
- Receive **only structured JSON Lines (JSONL)** as output (no TUI).
|
|
199
|
-
- Orchestrate BluMa as a **sub-agent** inside a larger architecture.
|
|
200
|
-
- Guarantee:
|
|
201
|
-
- Deterministic, parseable logs.
|
|
202
|
-
- A single, well-defined `result` event per execution.
|
|
203
|
-
- No interactive prompts or confirmation flows when running in sandbox.
|
|
204
|
-
|
|
205
|
-
### How to Call BluMa in Agent Mode
|
|
206
|
-
|
|
207
|
-
Agent mode is activated by passing the `agent` subcommand and piping a JSON envelope to stdin:
|
|
208
|
-
|
|
209
132
|
```bash
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
node dist/main.js agent --input - << 'EOF'
|
|
213
|
-
{
|
|
214
|
-
"message_id": "job-123",
|
|
215
|
-
"from_agent": "sandbox-api",
|
|
216
|
-
"to_agent": "bluma",
|
|
217
|
-
"action": "echo_test",
|
|
218
|
-
"context": {
|
|
219
|
-
"user_request": "Diz-me em uma frase o que é o bluma-cli."
|
|
220
|
-
},
|
|
221
|
-
"metadata": {
|
|
222
|
-
"sandbox": true
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
EOF
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
You can also use `--input-file` instead of stdin:
|
|
133
|
+
# Launch BluMa
|
|
134
|
+
bluma
|
|
229
135
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
node dist/main.js agent --input-file ./payload.json
|
|
136
|
+
# Or from local development
|
|
137
|
+
npm start
|
|
233
138
|
```
|
|
234
139
|
|
|
235
|
-
###
|
|
236
|
-
|
|
237
|
-
The JSON payload must follow this envelope:
|
|
140
|
+
### First Interaction
|
|
238
141
|
|
|
239
|
-
```json
|
|
240
|
-
{
|
|
241
|
-
"session_id": "conv-uuid-stable", // Recomendado: mesma sessão entre jobs (histórico + workspace)
|
|
242
|
-
"message_id": "job-123", // Opcional mas recomendado
|
|
243
|
-
"from_agent": "sandbox-api",
|
|
244
|
-
"to_agent": "bluma",
|
|
245
|
-
"action": "generate_app",
|
|
246
|
-
"context": {
|
|
247
|
-
"user_request": "Criar dashboard de vendas",
|
|
248
|
-
"erp_models": ["sale.order"],
|
|
249
|
-
"permissions": ["sales"]
|
|
250
|
-
},
|
|
251
|
-
"user_context": {
|
|
252
|
-
"userId": "13",
|
|
253
|
-
"userName": "Nome",
|
|
254
|
-
"userEmail": "user@example.com",
|
|
255
|
-
"companyId": "4",
|
|
256
|
-
"companyName": "Empresa",
|
|
257
|
-
"conversationId": null
|
|
258
|
-
},
|
|
259
|
-
"metadata": {
|
|
260
|
-
"sandbox": true,
|
|
261
|
-
"caller": "agiweb"
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
142
|
```
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
- Initialize the agent with a dedicated `eventBus`.
|
|
271
|
-
- Build a single user message containing this JSON.
|
|
272
|
-
- Run the normal reasoning + tool flow, but:
|
|
273
|
-
- **Without** rendering the Ink UI.
|
|
274
|
-
- **Without** asking for user confirmations when `BLUMA_SANDBOX=true`.
|
|
275
|
-
|
|
276
|
-
### Output: JSON Lines (JSONL)
|
|
277
|
-
|
|
278
|
-
In agent mode, BluMa writes **one JSON object per line** to stdout.
|
|
279
|
-
Typical events:
|
|
280
|
-
|
|
281
|
-
```json
|
|
282
|
-
{"event_type":"log","level":"info","message":"Starting agent mode execution","timestamp":"...","data":{"message_id":"job-123","action":"echo_test","from_agent":"sandbox-api","to_agent":"bluma"}}
|
|
283
|
-
{"event_type":"action_status","timestamp":"...","payload":{"action":"Thinking"}}
|
|
284
|
-
{"event_type":"backend_message","backend_type":"tool_call","timestamp":"...","payload":{"type":"tool_call","tool_name":"read_file_lines","arguments":{...}}}
|
|
285
|
-
{"event_type":"backend_message","backend_type":"tool_result","timestamp":"...","payload":{"type":"tool_result","tool_name":"read_file_lines","result":"{ ... }"}}
|
|
286
|
-
...
|
|
287
|
-
{"event_type":"result","status":"success","timestamp":"...","data":{"message_id":"job-123","action":"echo_test","last_assistant_message":"...","reasoning":null}}
|
|
143
|
+
> help me create a React component
|
|
144
|
+
> find all files containing "useEffect"
|
|
145
|
+
> run npm test in the background
|
|
146
|
+
> /tasks to see active tasks
|
|
147
|
+
> /model to switch LLM model
|
|
288
148
|
```
|
|
289
149
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
- **`event_type: "backend_message"`** mirrors what the CLI UI would receive (`tool_call`, `tool_result`, `reasoning`, `done`, etc.).
|
|
293
|
-
- **`event_type: "action_status"`** surfaces high-level states (Thinking, Reading, Executing, Waiting, Responding).
|
|
294
|
-
- **`event_type: "result"`** appears **exactly once** per execution and contains:
|
|
295
|
-
- `message_id`: propagated from the input.
|
|
296
|
-
- `action`: propagated from the input.
|
|
297
|
-
- `last_assistant_message`: the final message BluMa would send to a human (content of the `message` tool).
|
|
298
|
-
- `reasoning`: concatenated reasoning text when available (can be `null`).
|
|
299
|
-
- `attachments`: array of absolute file paths to deliverables generated by the agent (can be `null`).
|
|
300
|
-
|
|
301
|
-
### Artifact Delivery & File Lifecycle
|
|
302
|
-
|
|
303
|
-
BluMa in sandbox mode follows a strict file lifecycle to ensure deliverables are properly produced and delivered to the orchestrator:
|
|
304
|
-
|
|
305
|
-
**Workflow:**
|
|
306
|
-
1. **Analyse** — Parse the job request and plan what to produce.
|
|
307
|
-
2. **Script** — Write a Python script (e.g. `_task_runner.py`) to generate deliverables.
|
|
308
|
-
3. **Execute** — Run the script via `shell_command` (`python _task_runner.py`).
|
|
309
|
-
4. **Deliver** — Place all final documents in `./artifacts/` and include their **absolute paths** in the `attachments` field of the final `message` tool call.
|
|
310
|
-
5. **Clean up** — Delete temporary scripts and intermediate files, leaving only deliverables in `./artifacts/`.
|
|
311
|
-
|
|
312
|
-
**What goes in `attachments`:**
|
|
313
|
-
- Reports, CSVs, PDFs, spreadsheets, ZIPs, JSON exports, images — any file the user should consume.
|
|
314
|
-
- Always **absolute paths** (e.g. `/app/artifacts/sales_report.pdf`).
|
|
150
|
+
---
|
|
315
151
|
|
|
316
|
-
|
|
317
|
-
- Scripts (`.py`, `.sh`, `.ipynb`) used to generate the deliverables.
|
|
318
|
-
- Temporary or intermediate files (`.tmp`, `.log`, working data).
|
|
152
|
+
## Configuration
|
|
319
153
|
|
|
320
|
-
|
|
154
|
+
### Runtime Settings (`~/.bluma/settings.json`)
|
|
321
155
|
|
|
322
156
|
```json
|
|
323
157
|
{
|
|
324
|
-
"
|
|
325
|
-
"
|
|
326
|
-
"
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
"reasoning": "...",
|
|
331
|
-
"attachments": [
|
|
332
|
-
"/app/artifacts/sales_report_2026_Q1.pdf",
|
|
333
|
-
"/app/artifacts/sales_data_2026_Q1.csv"
|
|
334
|
-
]
|
|
335
|
-
}
|
|
158
|
+
"model": "gpt-4o",
|
|
159
|
+
"reasoningEffort": "medium",
|
|
160
|
+
"outputStyle": "concise",
|
|
161
|
+
"sandboxMode": "confirm",
|
|
162
|
+
"alwaysAcceptTools": ["read_file_lines", "grep_search"],
|
|
163
|
+
"theme": "default"
|
|
336
164
|
}
|
|
337
165
|
```
|
|
338
166
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
167
|
+
| Setting | Values | Description |
|
|
168
|
+
|---------|--------|-------------|
|
|
169
|
+
| `model` | `gpt-4o`, `gpt-4o-mini`, `claude-sonnet-4-20250514` | LLM model |
|
|
170
|
+
| `reasoningEffort` | `low`, `medium`, `high` | Reasoning depth |
|
|
171
|
+
| `outputStyle` | `concise`, `balanced`, `verbose` | Response style |
|
|
172
|
+
| `sandboxMode` | `confirm`, `auto`, `strict` | Tool execution policy |
|
|
344
173
|
|
|
345
|
-
|
|
346
|
-
- It is running **inside a non-interactive sandbox**.
|
|
347
|
-
- All inputs come from JSON payloads, not from a human on a terminal.
|
|
348
|
-
- Outputs must be deterministic, concise and suitable for machine parsing.
|
|
349
|
-
- It must follow a strict file lifecycle: produce → deliver → clean up.
|
|
350
|
-
- Tool execution:
|
|
351
|
-
- All tools are considered **auto-approved** in sandbox mode (no confirmation prompts from the user).
|
|
352
|
-
- This allows the orchestrator to let BluMa freely call `shell_command`, `command_status`, `coding_memory`, etc., while still observing every step through JSONL logs.
|
|
353
|
-
- Security:
|
|
354
|
-
- BluMa is **forbidden** from dumping, enumerating or exposing environment variables, API keys, tokens or any infrastructure details.
|
|
355
|
-
- Even if the user explicitly asks for env vars, BluMa will refuse and describe capabilities at a high level instead.
|
|
356
|
-
- This is a zero-tolerance policy — leaking env vars in a shared sandbox is a critical security breach.
|
|
174
|
+
### Directory Structure
|
|
357
175
|
|
|
358
|
-
### Example: Generating a Report
|
|
359
|
-
|
|
360
|
-
```bash
|
|
361
|
-
BLUMA_SANDBOX=true BLUMA_SANDBOX_NAME="sandbox-api" \
|
|
362
|
-
node dist/main.js agent --input - << 'EOF'
|
|
363
|
-
{
|
|
364
|
-
"message_id": "job-report-001",
|
|
365
|
-
"from_agent": "sandbox-api",
|
|
366
|
-
"to_agent": "bluma",
|
|
367
|
-
"action": "generate_report",
|
|
368
|
-
"context": {
|
|
369
|
-
"user_request": "Gera um relatório PDF com os dados de vendas do Q1 2026.",
|
|
370
|
-
"data_source": "sales_q1_2026.csv"
|
|
371
|
-
},
|
|
372
|
-
"metadata": {
|
|
373
|
-
"sandbox": true
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
EOF
|
|
377
176
|
```
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
4. Clean up the temporary script.
|
|
385
|
-
5. Emit the final `result` event:
|
|
386
|
-
|
|
387
|
-
```json
|
|
388
|
-
{
|
|
389
|
-
"event_type": "result",
|
|
390
|
-
"status": "success",
|
|
391
|
-
"data": {
|
|
392
|
-
"message_id": "job-report-001",
|
|
393
|
-
"action": "generate_report",
|
|
394
|
-
"last_assistant_message": "Relatório PDF gerado com sucesso com os dados de vendas Q1 2026.",
|
|
395
|
-
"reasoning": "...",
|
|
396
|
-
"attachments": ["/app/artifacts/sales_q1_2026_report.pdf"]
|
|
397
|
-
}
|
|
398
|
-
}
|
|
177
|
+
~/.bluma/
|
|
178
|
+
├── settings.json # Runtime configuration
|
|
179
|
+
├── coding_memory.json # Persistent coding notes
|
|
180
|
+
├── artifacts/ # Saved plans and documents
|
|
181
|
+
├── plugins/ # Global plugins
|
|
182
|
+
└── sessions/ # Session history
|
|
399
183
|
```
|
|
400
184
|
|
|
401
|
-
This makes it straightforward for an API layer (AGIWeb Sandbox, Severino, etc.) to:
|
|
402
|
-
|
|
403
|
-
- Orchestrate BluMa as a sub-agent.
|
|
404
|
-
- Log all intermediate steps.
|
|
405
|
-
- **Deliver generated files** to end users via the `attachments` array.
|
|
406
|
-
- Present only the final `last_assistant_message` (and optionally `reasoning`) to the end user.
|
|
407
|
-
|
|
408
185
|
---
|
|
409
186
|
|
|
410
|
-
##
|
|
411
|
-
|
|
412
|
-
Here's BluMa in action:
|
|
187
|
+
## Architecture
|
|
413
188
|
|
|
414
|
-

|
|
415
|
-
|
|
416
|
-
*BluMa's interactive CLI interface for conversational software engineering.*
|
|
417
|
-
|
|
418
|
-
---
|
|
419
|
-
|
|
420
|
-
## <a name="project-structure"></a>Project Structure
|
|
421
|
-
|
|
422
|
-
```
|
|
423
|
-
bluma-cli/
|
|
424
|
-
├── package.json # npm project config & dependencies
|
|
425
|
-
├── tsconfig.json # TypeScript configuration
|
|
426
|
-
├── babel.config.cjs # Babel presets for Jest/ESBuild
|
|
427
|
-
├── jest.config.cjs # Jest test configuration
|
|
428
|
-
├── scripts/
|
|
429
|
-
│ └── build.js # Build script using esbuild
|
|
430
|
-
├── src/
|
|
431
|
-
│ ├── main.ts # Entry point (CLI bootstrap & agent mode)
|
|
432
|
-
│ └── app/
|
|
433
|
-
│ ├── agent/ # Agent core & orchestration
|
|
434
|
-
│ │ ├── agent.ts # Main orchestrator (RouteManager integration)
|
|
435
|
-
│ │ ├── routeManager.ts # Route registration & dispatch
|
|
436
|
-
│ │ ├── bluma/
|
|
437
|
-
│ │ │ └── core/
|
|
438
|
-
│ │ │ └── bluma.ts # Core agent loop & state management
|
|
439
|
-
│ │ ├── config/
|
|
440
|
-
│ │ │ ├── native_tools.json # Native tool definitions
|
|
441
|
-
│ │ │ └── skills/ # Built-in skills (git-commit, git-pr, pdf, xlsx, skill-creator)
|
|
442
|
-
│ │ ├── core/
|
|
443
|
-
│ │ │ ├── context-api/ # Context management & token counting
|
|
444
|
-
│ │ │ │ ├── context_manager.ts
|
|
445
|
-
│ │ │ │ ├── history_anchor.ts
|
|
446
|
-
│ │ │ │ └── token_counter.ts
|
|
447
|
-
│ │ │ ├── llm/ # LLM client (FactorRouter/OpenAI SDK)
|
|
448
|
-
│ │ │ │ ├── llm.ts
|
|
449
|
-
│ │ │ │ └── tool_call_normalizer.ts
|
|
450
|
-
│ │ │ └── prompt/ # System prompt builder
|
|
451
|
-
│ │ │ └── prompt_builder.ts
|
|
452
|
-
│ │ ├── feedback/
|
|
453
|
-
│ │ │ └── feedback_system.ts # Smart feedback & suggestions
|
|
454
|
-
│ │ ├── session_manager/
|
|
455
|
-
│ │ │ └── session_manager.ts # Session persistence & history
|
|
456
|
-
│ │ ├── skills/
|
|
457
|
-
│ │ │ └── skill_loader.ts # Pluggable skill system
|
|
458
|
-
│ │ ├── subagents/ # Sub-agent implementations
|
|
459
|
-
│ │ │ ├── registry.ts # Sub-agent registration & lookup
|
|
460
|
-
│ │ │ ├── types.ts
|
|
461
|
-
│ │ │ ├── base_llm_subagent.ts
|
|
462
|
-
│ │ │ └── init/ # Init subagent (environment setup)
|
|
463
|
-
│ │ │ ├── init_subagent.ts
|
|
464
|
-
│ │ │ ├── init_system_prompt.ts
|
|
465
|
-
│ │ │ └── contracts.ts
|
|
466
|
-
│ │ ├── tools/
|
|
467
|
-
│ │ │ ├── mcp/
|
|
468
|
-
│ │ │ │ └── mcp_client.ts # MCP SDK integration
|
|
469
|
-
│ │ │ └── natives/ # Native tools (20+ tools)
|
|
470
|
-
│ │ │ ├── shell_command.ts
|
|
471
|
-
│ │ │ ├── edit.ts
|
|
472
|
-
│ │ │ ├── readLines.ts
|
|
473
|
-
│ │ │ ├── ls.ts
|
|
474
|
-
│ │ │ ├── grep_search.ts
|
|
475
|
-
│ │ │ ├── find_by_name.ts
|
|
476
|
-
│ │ │ ├── coding_memory.ts
|
|
477
|
-
│ │ │ ├── load_skill.ts
|
|
478
|
-
│ │ │ ├── message.ts
|
|
479
|
-
│ │ │ ├── todo.ts
|
|
480
|
-
│ │ │ ├── task_boundary.ts
|
|
481
|
-
│ │ │ └── ... (10 more)
|
|
482
|
-
│ │ ├── types/
|
|
483
|
-
│ │ │ └── index.ts # TypeScript type definitions
|
|
484
|
-
│ │ └── utils/
|
|
485
|
-
│ │ └── update_check.ts # Version update notifications
|
|
486
|
-
│ └── ui/ # Ink/React CLI interface
|
|
487
|
-
│ ├── App.tsx # Main React component
|
|
488
|
-
│ ├── layout.tsx # UI layout components
|
|
489
|
-
│ ├── components/ # Reusable UI components (20+)
|
|
490
|
-
│ │ ├── MarkdownRenderer.tsx
|
|
491
|
-
│ │ ├── ToolCallDisplay.tsx
|
|
492
|
-
│ │ ├── ToolResultCard.tsx
|
|
493
|
-
│ │ ├── InputPrompt.tsx
|
|
494
|
-
│ │ ├── ConfirmationPrompt.tsx
|
|
495
|
-
│ │ ├── SessionStats.tsx
|
|
496
|
-
│ │ └── ... (15 more)
|
|
497
|
-
│ ├── hooks/
|
|
498
|
-
│ │ └── useAtCompletion.ts # Autocomplete hook
|
|
499
|
-
│ ├── theme/
|
|
500
|
-
│ │ ├── blumaTerminal.ts
|
|
501
|
-
│ │ └── m3Layout.tsx
|
|
502
|
-
│ ├── utils/
|
|
503
|
-
│ │ ├── slashRegistry.ts
|
|
504
|
-
│ │ ├── terminalTitle.ts
|
|
505
|
-
│ │ └── ... (4 more)
|
|
506
|
-
│ └── Asci/
|
|
507
|
-
│ └── AsciiArt.ts
|
|
508
|
-
├── tests/ # Test suite (Jest 30)
|
|
509
|
-
│ ├── *.spec.ts # Unit & integration tests
|
|
510
|
-
│ └── *.spec.tsx # UI component tests
|
|
511
|
-
├── artifacts/ # Generated deliverables (runtime)
|
|
512
|
-
└── docs/ # Documentation
|
|
513
|
-
├── SKILLS.md # Skills system documentation
|
|
514
|
-
├── FACTOR_ROUTER_TURNS.md # FactorRouter integration details
|
|
515
|
-
└── assets/
|
|
516
|
-
└── bluma.png # Project logo
|
|
517
189
|
```
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
190
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
191
|
+
│ UI Layer │
|
|
192
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
|
|
193
|
+
│ │ App │ │ Input │ │ Slash │ │ ToolResult │ │
|
|
194
|
+
│ │ (Ink) │ │ Prompt │ │ Commands │ │ Display │ │
|
|
195
|
+
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬───────┘ │
|
|
196
|
+
└───────┼────────────┼────────────┼──────────────┼───────────┘
|
|
197
|
+
│ │ │ │
|
|
198
|
+
└────────────┴────────────┴──────────────┘
|
|
199
|
+
│
|
|
200
|
+
┌────────────────────────┼────────────────────────────────────┐
|
|
201
|
+
│ Agent Layer │
|
|
202
|
+
│ ┌──────────────┐ ┌──────────┐ ┌──────────────────────┐ │
|
|
203
|
+
│ │ Agent │ │ BluMa │ │ RouteManager │ │
|
|
204
|
+
│ │ Orchestrator│ │ Core │ │ (FactorRouter) │ │
|
|
205
|
+
│ └──────┬───────┘ └────┬─────┘ └──────────┬───────────┘ │
|
|
206
|
+
│ │ │ │ │
|
|
207
|
+
│ ┌──────┴───────┐ ┌────┴────┐ ┌───────────┴──────────┐ │
|
|
208
|
+
│ │ ToolInvoker │ │ LLM │ │ PromptBuilder │ │
|
|
209
|
+
│ │ │ │ Client │ │ + ContextManager │ │
|
|
210
|
+
│ └──────────────┘ └─────────┘ └──────────────────────┘ │
|
|
211
|
+
└─────────────────────────────────────────────────────────────┘
|
|
212
|
+
│
|
|
213
|
+
┌────────────────────────┼────────────────────────────────────┐
|
|
214
|
+
│ Runtime Layer │
|
|
215
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
|
|
216
|
+
│ │TaskStore │ │HookReg. │ │PluginReg.│ │SessionReg. │ │
|
|
217
|
+
│ │ │ │ │ │ │ │ │ │
|
|
218
|
+
│ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │
|
|
219
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
|
|
220
|
+
│ │Sandbox │ │ToolExec │ │Diagnostics│ │SessionView │ │
|
|
221
|
+
│ │Policy │ │Policy │ │ │ │ │ │
|
|
222
|
+
│ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │
|
|
223
|
+
└─────────────────────────────────────────────────────────────┘
|
|
224
|
+
│
|
|
225
|
+
┌────────────────────────┼────────────────────────────────────┐
|
|
226
|
+
│ Tools Layer │
|
|
227
|
+
│ ┌──────────────────────────────────────────────────────┐ │
|
|
228
|
+
│ │ Native Tools (25+) │ │
|
|
229
|
+
│ │ edit_tool, file_write, shell_command, grep_search, │ │
|
|
230
|
+
│ │ spawn_agent, todo, task_boundary, coding_memory, │ │
|
|
231
|
+
│ │ search_web, web_fetch, load_skill, ... │ │
|
|
232
|
+
│ └──────────────────────────────────────────────────────┘ │
|
|
233
|
+
│ ┌──────────────────────────────────────────────────────┐ │
|
|
234
|
+
│ │ MCP SDK Integration │ │
|
|
235
|
+
│ │ External tool servers via MCP │ │
|
|
236
|
+
│ └──────────────────────────────────────────────────────┘ │
|
|
237
|
+
└─────────────────────────────────────────────────────────────┘
|
|
537
238
|
```
|
|
538
239
|
|
|
539
240
|
---
|
|
540
241
|
|
|
541
|
-
##
|
|
542
|
-
|
|
543
|
-
|
|
242
|
+
## Native Tools
|
|
243
|
+
|
|
244
|
+
BluMa includes 25+ built-in tools organized by category:
|
|
245
|
+
|
|
246
|
+
### File Operations
|
|
247
|
+
| Tool | Description |
|
|
248
|
+
|------|-------------|
|
|
249
|
+
| `edit_tool` | Replace text in files (precise, multi-line) |
|
|
250
|
+
| `file_write` | Create/overwrite entire files |
|
|
251
|
+
| `read_file_lines` | Read specific line ranges |
|
|
252
|
+
| `count_file_lines` | Get file line count |
|
|
253
|
+
| `ls_tool` | List directories with filtering |
|
|
254
|
+
| `find_by_name` | Glob-based file search |
|
|
255
|
+
| `grep_search` | Text/regex search across files |
|
|
256
|
+
| `view_file_outline` | Show code structure (classes, functions) |
|
|
257
|
+
|
|
258
|
+
### Shell & Commands
|
|
259
|
+
| Tool | Description |
|
|
260
|
+
|------|-------------|
|
|
261
|
+
| `shell_command` | Execute background commands |
|
|
262
|
+
| `command_status` | Check command progress/output |
|
|
263
|
+
| `send_command_input` | Send input to running commands |
|
|
264
|
+
| `kill_command` | Terminate running commands |
|
|
544
265
|
|
|
545
|
-
|
|
266
|
+
### Agent Coordination
|
|
267
|
+
| Tool | Description |
|
|
268
|
+
|------|-------------|
|
|
269
|
+
| `spawn_agent` | Create background worker agents |
|
|
270
|
+
| `wait_agent` | Wait for agent completion |
|
|
271
|
+
| `list_agents` | List active/completed agents |
|
|
546
272
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
273
|
+
### Task & Project Management
|
|
274
|
+
| Tool | Description |
|
|
275
|
+
|------|-------------|
|
|
276
|
+
| `todo` | Manage task lists |
|
|
277
|
+
| `task_boundary` | Track task phases (PLANNING/EXECUTION/VERIFICATION) |
|
|
278
|
+
| `create_artifact` | Save documents to `~/.bluma/artifacts/` |
|
|
279
|
+
| `read_artifact` | Retrieve saved artifacts |
|
|
554
280
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
281
|
+
### Knowledge & Research
|
|
282
|
+
| Tool | Description |
|
|
283
|
+
|------|-------------|
|
|
284
|
+
| `search_web` | Search programming solutions (Reddit, GitHub, StackOverflow) |
|
|
285
|
+
| `web_fetch` | Fetch and analyze remote URLs |
|
|
286
|
+
| `load_skill` | Activate domain-specific skills |
|
|
287
|
+
| `coding_memory` | Persist/retrieve project notes |
|
|
558
288
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
- `kill_command` — Terminate running processes
|
|
289
|
+
### Communication
|
|
290
|
+
| Tool | Description |
|
|
291
|
+
|------|-------------|
|
|
292
|
+
| `message` | Post user-visible chat (info/result types) |
|
|
564
293
|
|
|
565
|
-
|
|
566
|
-
- `message` — Send messages to user (info or result)
|
|
567
|
-
- `todo` — Manage task lists with completion tracking
|
|
568
|
-
- `task_boundary` — Mark task phases (PLANNING, EXECUTION, VERIFICATION)
|
|
569
|
-
- `load_skill` — Load specialized knowledge modules
|
|
294
|
+
---
|
|
570
295
|
|
|
571
|
-
|
|
572
|
-
- All tools render rich Ink/React components in the terminal
|
|
296
|
+
## Skills System
|
|
573
297
|
|
|
574
|
-
|
|
298
|
+
Skills are **self-contained knowledge modules** that extend BluMa with domain expertise. They use **Progressive Disclosure** to manage context efficiently.
|
|
575
299
|
|
|
576
|
-
###
|
|
300
|
+
### Skill Sources (Priority Order)
|
|
577
301
|
|
|
578
|
-
|
|
302
|
+
| Priority | Source | Path |
|
|
303
|
+
|----------|--------|------|
|
|
304
|
+
| 1 | **Bundled** | `dist/config/skills/` |
|
|
305
|
+
| 2 | **Project** | `{cwd}/.bluma/skills/` |
|
|
306
|
+
| 3 | **Global** | `~/.bluma/skills/` |
|
|
579
307
|
|
|
580
|
-
|
|
581
|
-
- `git-commit` — Professional Git commit workflows with Conventional Commits
|
|
582
|
-
- `git-pr` — Pull request creation, commit validation, and merge preparation
|
|
583
|
-
- `pdf` — PDF creation, manipulation, text extraction, merging, OCR
|
|
584
|
-
- `xlsx` — Excel spreadsheet manipulation, formulas, data cleaning
|
|
585
|
-
- `skill-creator` — Template and workflow for creating new skills
|
|
308
|
+
### Progressive Disclosure Levels
|
|
586
309
|
|
|
587
|
-
**Skill Structure:**
|
|
588
310
|
```
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
311
|
+
Level 1: description (frontmatter)
|
|
312
|
+
Always visible. Cost: ~1 line per skill.
|
|
313
|
+
Purpose: Let agent DECIDE to activate.
|
|
314
|
+
|
|
315
|
+
↓ agent calls load_skill(name)
|
|
316
|
+
|
|
317
|
+
Level 2: SKILL.md body
|
|
318
|
+
Injected when activated. Cost: 50-300 lines.
|
|
319
|
+
Purpose: Core instructions and quick-start.
|
|
320
|
+
|
|
321
|
+
↓ agent reads reference or runs script (if needed)
|
|
322
|
+
|
|
323
|
+
Level 3a: references/*.md
|
|
324
|
+
Read on-demand. Cost: only when read.
|
|
325
|
+
Purpose: Advanced documentation.
|
|
326
|
+
|
|
327
|
+
Level 3b: scripts/*.py
|
|
328
|
+
Executed on-demand. Cost: zero context.
|
|
329
|
+
Purpose: Pre-built utilities.
|
|
597
330
|
```
|
|
598
331
|
|
|
599
|
-
|
|
600
|
-
1. Skills are stored in `src/app/agent/config/skills/` (built-in) or `~/.bluma/skills/` (user)
|
|
601
|
-
2. Each skill includes a `SKILL.md` with YAML frontmatter defining:
|
|
602
|
-
- `name`, `description`, `version`
|
|
603
|
-
- `depends_on` (other skills for delegation)
|
|
604
|
-
- `tools.required` and `tools.recommended`
|
|
605
|
-
3. Load a skill with: `load_skill({ skill_name: "git-commit" })`
|
|
606
|
-
4. Skill body provides workflows, examples, and decision trees
|
|
607
|
-
5. Skills can include `references/` (extra docs) and `scripts/` (Python helpers)
|
|
608
|
-
|
|
609
|
-
**Creating Custom Skills:**
|
|
610
|
-
Use the `skill-creator` skill to generate new skill templates. Skills are ideal for:
|
|
611
|
-
- Encoding domain-specific workflows (testing, deployment, frameworks)
|
|
612
|
-
- Packaging best practices and conventions
|
|
613
|
-
- Providing reusable scripts and reference documentation
|
|
614
|
-
|
|
615
|
-
### MCP Integration
|
|
616
|
-
|
|
617
|
-
BluMa integrates with the **Model Context Protocol (MCP)** SDK for:
|
|
618
|
-
- Connecting to external MCP servers
|
|
619
|
-
- Discovering and invoking remote tools
|
|
620
|
-
- Streaming tool results in real-time
|
|
621
|
-
|
|
622
|
-
MCP client is located at `src/app/agent/tools/mcp/mcp_client.ts`.
|
|
623
|
-
|
|
624
|
-
### Custom UI Components
|
|
332
|
+
### Available Skills
|
|
625
333
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
-
|
|
629
|
-
-
|
|
630
|
-
|
|
631
|
-
|
|
334
|
+
| Skill | Description |
|
|
335
|
+
|-------|-------------|
|
|
336
|
+
| `git-commit` | Conventional commits, staging, commit messages |
|
|
337
|
+
| `git-pr` | Pull requests, code review preparation |
|
|
338
|
+
| `pdf` | PDF creation, extraction, merging, OCR |
|
|
339
|
+
| `xlsx` | Spreadsheet operations, formulas, charts |
|
|
340
|
+
| `skill-creator` | Author new BluMa skills |
|
|
632
341
|
|
|
633
|
-
|
|
342
|
+
### Loading Skills
|
|
634
343
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
- Run tests:
|
|
344
|
+
```typescript
|
|
345
|
+
// Via command
|
|
346
|
+
> load the git-commit skill
|
|
639
347
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
npm run test:watch
|
|
348
|
+
// Via tool call
|
|
349
|
+
load_skill({ skill_name: "git-commit" })
|
|
643
350
|
```
|
|
644
351
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
Key points
|
|
651
|
-
- Permissive mode enabled: during processing, any free text you type is treated as a [hint] automatically.
|
|
652
|
-
- Structured prefixes are also supported at any time:
|
|
653
|
-
- [hint] Text for immediate guidance to the agent
|
|
654
|
-
- [constraint] Rules/limits (e.g., "não tocar em src/app/agent/**")
|
|
655
|
-
- [override] Parameter overrides as key=value pairs (e.g., "file_path=C:/... expected_replacements=2")
|
|
656
|
-
- [assume] Register explicit assumptions
|
|
657
|
-
- [cancel] Interrupt safely (already supported)
|
|
658
|
-
|
|
659
|
-
How it works
|
|
660
|
-
- Frontend: the input remains active in read-only (processing) mode and emits a dev_overlay event.
|
|
661
|
-
- Agent backend: consumes overlays with precedence (constraint > override > hint). Hints and assumptions are injected into the system context before the next decision; overrides/constraints adjust tool parameters just before execution.
|
|
662
|
-
- Logging & history: every overlay is logged and stored in session history for auditability.
|
|
663
|
-
|
|
664
|
-
Examples
|
|
665
|
-
- During a long task, just type:
|
|
666
|
-
- "Prefer do not touch tests yet" → will be treated as [hint]
|
|
667
|
-
- "[constraint] não editar src/app/ui/**" → blocks edits under that path
|
|
668
|
-
- "[override] expected_replacements=2" → adjusts the next edit_tool call
|
|
669
|
-
- "[assume] target=api" → adds an assumption in context
|
|
670
|
-
|
|
671
|
-
Notes
|
|
672
|
-
- The side-channel does not pause the agent — it adapts on the fly.
|
|
673
|
-
- If an overlay conflicts with the current plan: constraint > override > hint.
|
|
674
|
-
- All overlays are acknowledged via standard internal messages and persisted.
|
|
675
|
-
|
|
676
|
-
---
|
|
677
|
-
|
|
678
|
-
## <a name="configuration-and-environment-variables"></a>Configuration and Environment Variables
|
|
679
|
-
|
|
680
|
-
**Recommended:** set **`FACTOR_ROUTER_KEY`** and **`FACTOR_ROUTER_URL`** in your **user or system environment** (shell profile, Windows User env, CI secrets, etc.) so every process sees them.
|
|
681
|
-
|
|
682
|
-
BluMa also **loads** `~/.bluma/.env` if that file exists (optional merge via `dotenv`); use `.env.example` as a template only if you prefer a local file.
|
|
683
|
-
|
|
684
|
-
**LLM routing** uses the FactorRouter gateway (OpenAI-compatible API):
|
|
685
|
-
|
|
686
|
-
- `FACTOR_ROUTER_KEY` (required) — e.g. `sk-fai-...` from your FactorRouter admin
|
|
687
|
-
- `FACTOR_ROUTER_URL` (required) — gateway base URL (e.g. `http://host:8003/router-api`; the client appends `/v1` if missing)
|
|
688
|
-
|
|
689
|
-
These replace legacy `NOMAD_API_KEY`, `NOMAD_BASE_URL`, and `MODEL_NOMAD` (the router picks the model; requests use `model: "auto"`).
|
|
690
|
-
|
|
691
|
-
Optional: `BLUMA_SANDBOX`, `BLUMA_SANDBOX_NAME`, MCP tokens, etc.
|
|
692
|
-
|
|
693
|
-
### FactorRouter — headers HTTP (CLI vs sandbox)
|
|
694
|
-
|
|
695
|
-
O SDK OpenAI (`openai` npm) envia metadados no **2.º argumento** da chamada `chat.completions.create(body, { headers })` — são **headers HTTP normais**, não um campo `extra_headers` no JSON do body.
|
|
696
|
-
|
|
697
|
-
**Modo CLI interativo** (Ink, sem envelope): em cada request ao gateway são acrescentados:
|
|
698
|
-
|
|
699
|
-
| Header | Conteúdo típico (exemplo) |
|
|
700
|
-
|--------|---------------------------|
|
|
701
|
-
| `X-Turn-Id` | UUID novo por turno (igual em todo o loop de tools desse turno) |
|
|
702
|
-
| `X-Session-Id` | ID da sessão BluMa (`~/.bluma/sessions/…`) |
|
|
703
|
-
| `X-Conversation-Id` | `null` |
|
|
704
|
-
| `X-User-Message` | Primeiros 300 caracteres do pedido (URL-encoded) |
|
|
705
|
-
| `X-User-Id` | MAC da 1.ª interface não-interna, ou `host:<hostname>` se não houver MAC útil |
|
|
706
|
-
| `X-User-Name` | Utilizador do SO (`os.userInfo().username`, URL-encoded) |
|
|
707
|
-
| `X-User-Email` | `null` |
|
|
708
|
-
| `X-Company-Id` | Igual a `X-User-Id` (identificador da máquina) |
|
|
709
|
-
| `X-Company-Name` | Igual (URL-encoded) |
|
|
710
|
-
|
|
711
|
-
**Privacidade (desenvolvedores):** na CLI, estes valores servem para **agregação de custos** no FactorRouter. Não substituem o utilizador real no **agent mode**: aí prevalece o bloco `user_context` do JSON (sandbox / Severino).
|
|
712
|
-
|
|
713
|
-
**Agent mode** (`bluma agent`): os mesmos nomes de header; valores vêm do envelope (`session_id`, `user_context`, `context.user_request`). Se `user_context` for omitido, user/company ficam `null` nos headers (não se usa a heurística MAC da CLI).
|
|
714
|
-
|
|
715
|
-
Advanced config files are located in `src/app/agent/config/`.
|
|
352
|
+
Skills inject domain knowledge and best practices into the agent's context. Each skill has:
|
|
353
|
+
- **Frontmatter**: Description and dependencies (always visible)
|
|
354
|
+
- **Body**: Core instructions (injected on activation)
|
|
355
|
+
- **References**: Advanced docs (read on-demand)
|
|
356
|
+
- **Scripts**: Executable utilities (zero context cost)
|
|
716
357
|
|
|
717
358
|
---
|
|
718
359
|
|
|
719
|
-
##
|
|
720
|
-
- Language: TypeScript (ESM)
|
|
721
|
-
- Runtime: Node.js >= 18
|
|
722
|
-
- CLI UI: React 18 via Ink 5, plus `ink-text-input`, `ink-spinner`, `ink-big-text`
|
|
723
|
-
- Bundler: esbuild, with `esbuild-plugin-node-externals`
|
|
724
|
-
- Test Runner: Jest 30 + babel-jest
|
|
725
|
-
- Transpilers: Babel presets (env, react, typescript)
|
|
726
|
-
- LLM/Agent: FactorRouter (OpenAI-compatible API); MCP via `@modelcontextprotocol/sdk`
|
|
727
|
-
- Config loading: dotenv
|
|
728
|
-
- Utilities: uuid, diff, react-devtools-core
|
|
729
|
-
|
|
730
|
-
---
|
|
731
|
-
|
|
732
|
-
## <a name="license"></a>License
|
|
733
|
-
Apache-2.0. Made by Alex Fonseca and NomadEngenuity contributors.
|
|
734
|
-
|
|
735
|
-
Enjoy, hack, and—if possible—contribute!
|
|
736
|
-
|
|
737
|
-
---
|
|
360
|
+
## Runtime & Orchestration
|
|
738
361
|
|
|
739
|
-
|
|
362
|
+
### Task Store
|
|
740
363
|
|
|
741
|
-
|
|
364
|
+
Track work with PLANNING → EXECUTION → VERIFICATION phases:
|
|
742
365
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
↓
|
|
750
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
751
|
-
│ Agent Orchestration Layer │
|
|
752
|
-
│ agent.ts → RouteManager → BluMaAgent (bluma.ts) │
|
|
753
|
-
│ ↓ │
|
|
754
|
-
│ SubAgents Registry | Feedback System | Session Manager │
|
|
755
|
-
└─────────────────────────────────────────────────────────────┘
|
|
756
|
-
↓
|
|
757
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
758
|
-
│ Core Services Layer │
|
|
759
|
-
│ ┌──────────────┬──────────────┬──────────────┐ │
|
|
760
|
-
│ │ Context API │ LLM Client │ Prompt Bld │ │
|
|
761
|
-
│ │ (context │ (Factor │ (system │ │
|
|
762
|
-
│ │ manager) │ Router) │ prompts) │ │
|
|
763
|
-
│ └──────────────┴──────────────┴──────────────┘ │
|
|
764
|
-
│ ┌──────────────┬──────────────┬──────────────┐ │
|
|
765
|
-
│ │ MCP Client │ Native Tools │ Skills │ │
|
|
766
|
-
│ │ (external │ (20+ tools) │ (pluggable) │ │
|
|
767
|
-
│ │ plugins) │ │ │ │
|
|
768
|
-
│ └──────────────┴──────────────┴──────────────┘ │
|
|
769
|
-
└─────────────────────────────────────────────────────────────┘
|
|
770
|
-
↓
|
|
771
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
772
|
-
│ External Integrations │
|
|
773
|
-
│ FactorRouter API | File System | Shell | MCP Servers │
|
|
774
|
-
└─────────────────────────────────────────────────────────────┘
|
|
366
|
+
```typescript
|
|
367
|
+
task_boundary({
|
|
368
|
+
task_name: "Implementing Authentication",
|
|
369
|
+
mode: "PLANNING",
|
|
370
|
+
task_status: "Creating middleware structure"
|
|
371
|
+
});
|
|
775
372
|
```
|
|
776
373
|
|
|
777
|
-
###
|
|
778
|
-
|
|
779
|
-
**1. RouteManager Pattern**
|
|
780
|
-
- Central dispatch mechanism for command routing
|
|
781
|
-
- Registers custom route handlers (e.g., `/init`, `/status`)
|
|
782
|
-
- Falls back to core agent loop for unregistered commands
|
|
783
|
-
- Enables extensible command architecture
|
|
784
|
-
|
|
785
|
-
**2. SubAgents Registry**
|
|
786
|
-
- Pluggable sub-agent system for specialized tasks
|
|
787
|
-
- Each sub-agent declares capabilities via registry
|
|
788
|
-
- Init subagent handles environment setup
|
|
789
|
-
- Extensible via `registerSubAgent()` API
|
|
790
|
-
|
|
791
|
-
**3. Context Management**
|
|
792
|
-
- `ContextManager` handles conversation history
|
|
793
|
-
- `TokenCounter` tracks token usage (tiktoken)
|
|
794
|
-
- `HistoryAnchor` manages context window compression
|
|
795
|
-
- Automatic pruning to stay within LLM limits
|
|
796
|
-
|
|
797
|
-
**4. Session Persistence**
|
|
798
|
-
- `SessionManager` persists all interactions
|
|
799
|
-
- Stored in `~/.bluma/sessions/<session-id>.json`
|
|
800
|
-
- Survives across CLI restarts
|
|
801
|
-
- Includes full tool call history and results
|
|
802
|
-
|
|
803
|
-
**5. Skills System**
|
|
804
|
-
- Pluggable knowledge modules (`skill_loader.ts`)
|
|
805
|
-
- Built-in skills: `git-commit`, `git-pr`, `pdf`, `xlsx`, `skill-creator`
|
|
806
|
-
- Each skill includes `SKILL.md` with workflows
|
|
807
|
-
- Can include `references/` (docs) and `scripts/` (executables)
|
|
808
|
-
|
|
809
|
-
### Sequence Diagram
|
|
810
|
-
```mermaid
|
|
811
|
-
sequenceDiagram
|
|
812
|
-
participant UI as UI (main.ts + App.tsx)
|
|
813
|
-
participant Agent as Agent (Orchestrator)
|
|
814
|
-
participant Core as BluMaAgent (Core Loop)
|
|
815
|
-
participant MCP as MCPClient / Tools
|
|
816
|
-
|
|
817
|
-
UI->>Agent: Initialize(sessionId, eventBus)
|
|
818
|
-
Agent->>Core: initialize()
|
|
819
|
-
Core->>MCP: initialize tools
|
|
820
|
-
UI->>Agent: processTurn(userInput)
|
|
821
|
-
Agent->>Core: processTurn(content)
|
|
822
|
-
Core->>MCP: Get available tools & context
|
|
823
|
-
MCP-->>Core: Tool list & details
|
|
824
|
-
Core-->>Agent: Tool call request or LLM message
|
|
825
|
-
Agent-->>UI: backend_message (e.g., confirmation_request)
|
|
826
|
-
UI->>Agent: handleToolResponse()
|
|
827
|
-
Agent->>Core: handleToolResponse(decision)
|
|
828
|
-
Core->>MCP: Execute tool
|
|
829
|
-
MCP-->>Core: Tool result
|
|
830
|
-
Core-->>Agent: backend_message(done)
|
|
831
|
-
Agent-->>UI: Update history & UI state
|
|
832
|
-
```
|
|
374
|
+
### Hook Registry
|
|
833
375
|
|
|
834
|
-
|
|
376
|
+
Event-driven lifecycle tracking:
|
|
835
377
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
A["App.tsx"]
|
|
842
|
-
end
|
|
843
|
-
subgraph AG["Agent Layer"]
|
|
844
|
-
AGN["Agent (Orchestrator)"]
|
|
845
|
-
CORE["BluMaAgent (Core Loop)"]
|
|
846
|
-
end
|
|
847
|
-
subgraph TOOLS["Tools & Integration"]
|
|
848
|
-
MCP["MCPClient"]
|
|
849
|
-
NT["Native Tools"]
|
|
850
|
-
SA["SubAgents"]
|
|
851
|
-
end
|
|
852
|
-
EXT["External APIs & FS"]
|
|
853
|
-
|
|
854
|
-
M --> A --> AGN --> CORE --> MCP --> NT
|
|
855
|
-
CORE --> SA
|
|
856
|
-
MCP --> EXT
|
|
857
|
-
NT --> EXT
|
|
378
|
+
```typescript
|
|
379
|
+
// Hooks fire on: tool_calls, decisions, state_changes
|
|
380
|
+
registerHook('tool_calls', (event) => {
|
|
381
|
+
console.log(`Tool ${event.toolName} executed`);
|
|
382
|
+
});
|
|
858
383
|
```
|
|
859
384
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
### Activity Diagram
|
|
863
|
-
```mermaid
|
|
864
|
-
flowchart TD
|
|
865
|
-
Start((Start)) --> Input[User Input in UI]
|
|
866
|
-
Input --> Processing{Command Type?}
|
|
867
|
-
Processing -->|Slash Command| SC[Handle Slash Command]
|
|
868
|
-
Processing -->|Normal Input| PT[processTurn]
|
|
869
|
-
SC --> Done((End))
|
|
870
|
-
PT --> LLM[Send to LLM]
|
|
871
|
-
LLM --> ToolCall{Tool Requested?}
|
|
872
|
-
ToolCall -->|No| Display[Display Assistant Message]
|
|
873
|
-
ToolCall -->|Yes| Confirm[Ask for Confirmation]
|
|
874
|
-
Confirm --> Decision{Decision}
|
|
875
|
-
Decision -->|Accept| Exec[Execute Tool]
|
|
876
|
-
Decision -->|Decline| Skip[Skip Execution]
|
|
877
|
-
Exec --> Result[Return Tool Result]
|
|
878
|
-
Skip --> Done
|
|
879
|
-
Result --> Done
|
|
880
|
-
Display --> Done
|
|
881
|
-
```
|
|
385
|
+
### Plugin Registry
|
|
882
386
|
|
|
883
|
-
|
|
387
|
+
Load plugins from `.bluma/plugins/`:
|
|
884
388
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
[*] --> Idle
|
|
889
|
-
Idle --> Processing: User Input
|
|
890
|
-
Processing --> Awaiting_Confirmation: Tool Call Needs Approval
|
|
891
|
-
Awaiting_Confirmation --> Processing: User Accepts
|
|
892
|
-
Awaiting_Confirmation --> Idle: User Declines
|
|
893
|
-
Processing --> Completed: Task Completed
|
|
894
|
-
Processing --> Interrupted: User Interrupt
|
|
895
|
-
Completed --> Idle
|
|
896
|
-
Interrupted --> Idle
|
|
389
|
+
```bash
|
|
390
|
+
> /plugins list # Show loaded plugins
|
|
391
|
+
> /plugins load my-plugin # Load a plugin
|
|
897
392
|
```
|
|
898
393
|
|
|
899
|
-
|
|
394
|
+
### Session Registry
|
|
900
395
|
|
|
901
|
-
|
|
902
|
-
```mermaid
|
|
903
|
-
graph TD
|
|
904
|
-
CLI["CLI (BluMa)"] --> LocalFS[("Local File System")]
|
|
905
|
-
CLI --> FactorRouter[("FactorRouter API")]
|
|
906
|
-
CLI --> OtherAPIs[("Other External APIs")]
|
|
907
|
-
CLI --> MCPServer[("MCP Server / Plugins")]
|
|
908
|
-
```
|
|
909
|
-
|
|
910
|
-
---
|
|
396
|
+
Multi-session support with health monitoring:
|
|
911
397
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
UI --> Agent[Agent]
|
|
917
|
-
Agent --> Core[BluMaAgent]
|
|
918
|
-
Core --> MCP[MCPClient]
|
|
919
|
-
Core --> Sub[SubAgents]
|
|
920
|
-
MCP --> Tools[Native Tools & External APIs]
|
|
921
|
-
Sub --> Tools
|
|
922
|
-
Tools --> MCP
|
|
923
|
-
MCP --> Core
|
|
924
|
-
Core --> Agent
|
|
925
|
-
Agent --> UI
|
|
926
|
-
UI --> U
|
|
398
|
+
```bash
|
|
399
|
+
> /sessions list # List all sessions
|
|
400
|
+
> /sessions logs <id> # Stream session logs
|
|
401
|
+
> /sessions kill <id> # Terminate session
|
|
927
402
|
```
|
|
928
403
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
## 💡 Usage Examples
|
|
404
|
+
### Diagnostics
|
|
932
405
|
|
|
933
|
-
|
|
406
|
+
Real-time system snapshot:
|
|
934
407
|
|
|
935
|
-
**1. Start a Conversation**
|
|
936
408
|
```bash
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
409
|
+
> /diagnostics # Full system status
|
|
410
|
+
> /diagnostics tasks # Task overview
|
|
411
|
+
> /diagnostics hooks # Hook registry status
|
|
412
|
+
> /diagnostics plugins # Plugin registry status
|
|
413
|
+
> /diagnostics sessions # Active sessions
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Runtime Files
|
|
417
|
+
|
|
418
|
+
| File | Purpose |
|
|
419
|
+
|------|---------|
|
|
420
|
+
| `~/.bluma/task_state.json` | Persistent task tracking |
|
|
421
|
+
| `~/.bluma/hooks.json` | Hook registry state |
|
|
422
|
+
| `~/.bluma/sessions/` | Session history and logs |
|
|
423
|
+
| `~/.bluma/plugins/` | Global plugin storage |
|
|
424
|
+
|
|
425
|
+
### Tool Execution Policy
|
|
426
|
+
|
|
427
|
+
BluMa uses intelligent tool execution based on sandbox mode:
|
|
428
|
+
|
|
429
|
+
| Sandbox Mode | Behavior |
|
|
430
|
+
|--------------|----------|
|
|
431
|
+
| `confirm` | Prompt for dangerous tools (shell, edit, write) |
|
|
432
|
+
| `auto` | Auto-approve safe tools, confirm risky ones |
|
|
433
|
+
| `strict` | Require confirmation for all tools |
|
|
434
|
+
|
|
435
|
+
Safe tools (always auto-approved): `read_file_lines`, `grep_search`, `ls_tool`, `find_by_name`, `count_file_lines`, `view_file_outline`
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## Slash Commands
|
|
440
|
+
|
|
441
|
+
Built-in terminal commands (type `/` to see all):
|
|
442
|
+
|
|
443
|
+
### Session & UI
|
|
444
|
+
| Command | Description |
|
|
445
|
+
|---------|-------------|
|
|
446
|
+
| `/clear` | Clear chat below welcome panel |
|
|
447
|
+
| `/sessions` | Show registered sessions (current + historical) |
|
|
448
|
+
| `/attach <id>` | Live-follow a session log stream |
|
|
449
|
+
| `/follow <id>` | Alias of /attach for live session follow |
|
|
450
|
+
| `/bridge` | Show session bridge state and follow instructions |
|
|
451
|
+
| `/status <id>` | Show session status for a session id |
|
|
452
|
+
| `/logs <id>` | Show recent logs for a session id |
|
|
453
|
+
| `/resume <id>` | Resume a session from the current CLI |
|
|
454
|
+
| `/kill <id>` | Send SIGTERM to a session by id |
|
|
455
|
+
| `/tasks [list\|add\|complete\|update\|remove\|clear]` | Manage task list |
|
|
456
|
+
| `/plan [show\|start\|end]` | Manage the active task boundary |
|
|
457
|
+
|
|
458
|
+
### Agent
|
|
459
|
+
| Command | Description |
|
|
460
|
+
|---------|-------------|
|
|
461
|
+
| `/img ./shot.png [question]` | Send local image(s) to the model |
|
|
462
|
+
| `/image` | Alias of /img |
|
|
463
|
+
| `/init` | Run init subagent — BluMa.md codebase documentation |
|
|
464
|
+
|
|
465
|
+
### Inspect
|
|
466
|
+
| Command | Description |
|
|
467
|
+
|---------|-------------|
|
|
468
|
+
| `/plugins` | List installed plugins and plugin paths |
|
|
469
|
+
| `/plugin <name>` | Inspect one plugin |
|
|
470
|
+
| `/diagnostics` | Show a consolidated health snapshot |
|
|
471
|
+
| `/permissions` | Inspect sandbox and tool execution rules |
|
|
472
|
+
| `/hooks` | Inspect, enable, disable, or clear lifecycle hooks |
|
|
473
|
+
| `/model [list\|name\|auto]` | Show, list, or set the active model |
|
|
474
|
+
| `/effort [low\|medium\|high]` | Show or set reasoning effort |
|
|
475
|
+
| `/style [default\|compact\|brief]` | Show or set output style |
|
|
476
|
+
| `/sandbox [on\|off]` | Show or toggle sandbox mode |
|
|
477
|
+
| `/worktree [path]` | Show or set workspace root |
|
|
478
|
+
| `/statusline` | Show the current session statusline summary |
|
|
479
|
+
| `/skills` | List load_skill modules, dirs, and conflicts |
|
|
480
|
+
| `/tools [grep]` | List native tools (optional filter) |
|
|
481
|
+
| `/mcp [fs]` | List MCP tools (optional filter) |
|
|
482
|
+
|
|
483
|
+
### Help
|
|
484
|
+
| Command | Description |
|
|
485
|
+
|---------|-------------|
|
|
486
|
+
| `/help` | List all slash commands (grouped) |
|
|
487
|
+
|
|
488
|
+
### Input (Keyboard Shortcuts)
|
|
489
|
+
| Shortcut | Description |
|
|
490
|
+
|----------|-------------|
|
|
491
|
+
| `Ctrl+V / Cmd+V` | Paste from clipboard: image → file path under ~/.cache/bluma/clipboard; else text |
|
|
492
|
+
| `Ctrl+Shift+I` | Same as Ctrl+V / Cmd+V (paste image or text) |
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Development
|
|
497
|
+
|
|
498
|
+
### Build
|
|
943
499
|
|
|
944
|
-
**2. Use Slash Commands**
|
|
945
500
|
```bash
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
/memory list # List all coding memory entries
|
|
949
|
-
/skills # List available skills
|
|
950
|
-
```
|
|
951
|
-
|
|
952
|
-
**3. Load Skills for Specialized Tasks**
|
|
953
|
-
```
|
|
954
|
-
# The agent will automatically load skills when needed
|
|
955
|
-
"Commit these changes with a proper message" → loads git-commit skill
|
|
956
|
-
"Create a pull request" → loads git-pr skill
|
|
957
|
-
"Generate a PDF report" → loads pdf skill
|
|
958
|
-
"Analyze this Excel file" → loads xlsx skill
|
|
501
|
+
npm run build # Production build
|
|
502
|
+
npm start # Build + run
|
|
959
503
|
```
|
|
960
504
|
|
|
961
|
-
|
|
962
|
-
While the agent is working, type guidance:
|
|
963
|
-
```
|
|
964
|
-
[hint] Focus on the authentication flow first
|
|
965
|
-
[constraint] Don't modify files in tests/ yet
|
|
966
|
-
[override] expected_replacements=2
|
|
967
|
-
[assume] target_database=postgresql
|
|
968
|
-
```
|
|
969
|
-
|
|
970
|
-
**5. Tool Confirmation Flow**
|
|
971
|
-
When the agent requests a sensitive operation:
|
|
972
|
-
```
|
|
973
|
-
┌─────────────────────────────────────────┐
|
|
974
|
-
│ EDIT PREVIEW │
|
|
975
|
-
│ File: src/auth/login.ts │
|
|
976
|
-
│ Lines 45-67 │
|
|
977
|
-
│ │
|
|
978
|
-
│ - old code │
|
|
979
|
-
│ + new code │
|
|
980
|
-
└─────────────────────────────────────────┘
|
|
981
|
-
|
|
982
|
-
[Accept] [Decline] [Accept Always] [Expand]
|
|
983
|
-
```
|
|
505
|
+
### Lint
|
|
984
506
|
|
|
985
|
-
### Agent Mode (Sandbox / API Integration)
|
|
986
|
-
|
|
987
|
-
**6. Call BluMa from Another System**
|
|
988
507
|
```bash
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
508
|
+
npm run lint # Check code style
|
|
509
|
+
npm run lint:fix # Auto-fix issues
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### Project Structure
|
|
513
|
+
|
|
514
|
+
```
|
|
515
|
+
src/
|
|
516
|
+
├── app/
|
|
517
|
+
│ ├── agent/
|
|
518
|
+
│ │ ├── agent.ts # Main orchestrator
|
|
519
|
+
│ │ ├── bluma/ # Core agent logic
|
|
520
|
+
│ │ ├── core/ # LLM, context, prompts
|
|
521
|
+
│ │ │ ├── context-api/ # Context management
|
|
522
|
+
│ │ │ │ ├── context_manager.ts # Token-aware context
|
|
523
|
+
│ │ │ │ ├── history_anchor.ts # Conversation anchoring
|
|
524
|
+
│ │ │ │ └── token_counter.ts # Tiktoken integration
|
|
525
|
+
│ │ │ ├── llm/ # LLM client
|
|
526
|
+
│ │ │ │ ├── llm.ts # FactorRouter client
|
|
527
|
+
│ │ │ │ └── tool_call_normalizer.ts
|
|
528
|
+
│ │ │ └── prompt/ # Prompt engineering
|
|
529
|
+
│ │ │ ├── prompt_builder.ts # Dynamic prompts
|
|
530
|
+
│ │ │ └── workspace_snapshot.ts
|
|
531
|
+
│ │ ├── runtime/ # Orchestration layer (v0.1.41+)
|
|
532
|
+
│ │ │ ├── diagnostics.ts # System snapshots
|
|
533
|
+
│ │ │ ├── hook_registry.ts # Event-driven hooks
|
|
534
|
+
│ │ │ ├── native_tool_catalog.ts # Tool registry
|
|
535
|
+
│ │ │ ├── plugin_registry.ts # Plugin system
|
|
536
|
+
│ │ │ ├── runtime_config.ts # Runtime settings
|
|
537
|
+
│ │ │ ├── sandbox_policy.ts # Safety policies
|
|
538
|
+
│ │ │ ├── session_registry.ts # Multi-session mgmt
|
|
539
|
+
│ │ │ ├── session_view.ts # Session monitoring
|
|
540
|
+
│ │ │ ├── task_store.ts # Task lifecycle
|
|
541
|
+
│ │ │ └── tool_execution_policy.ts
|
|
542
|
+
│ │ ├── tools/ # Tool layer
|
|
543
|
+
│ │ │ └── natives/ # 18 native tools
|
|
544
|
+
│ │ │ ├── agent_coordination.ts
|
|
545
|
+
│ │ │ ├── async_command.ts
|
|
546
|
+
│ │ │ ├── coding_memory.ts
|
|
547
|
+
│ │ │ ├── edit.ts
|
|
548
|
+
│ │ │ ├── file_write.ts
|
|
549
|
+
│ │ │ ├── find_by_name.ts
|
|
550
|
+
│ │ │ ├── grep_search.ts
|
|
551
|
+
│ │ │ ├── load_skill.ts
|
|
552
|
+
│ │ │ ├── ls.ts
|
|
553
|
+
│ │ │ ├── message.ts
|
|
554
|
+
│ │ │ ├── readLines.ts
|
|
555
|
+
│ │ │ ├── search_web.ts
|
|
556
|
+
│ │ │ ├── shell_command.ts
|
|
557
|
+
│ │ │ ├── task_boundary.ts
|
|
558
|
+
│ │ │ ├── todo.ts
|
|
559
|
+
│ │ │ ├── view_file_outline.ts
|
|
560
|
+
│ │ │ └── web_fetch.ts
|
|
561
|
+
│ │ └── types/ # TypeScript definitions
|
|
562
|
+
│ └── ui/
|
|
563
|
+
│ ├── App.tsx # Main UI component
|
|
564
|
+
│ ├── components/ # 21 UI components
|
|
565
|
+
│ │ ├── AnimatedBorder.tsx
|
|
566
|
+
│ │ ├── CollapsibleResult.tsx
|
|
567
|
+
│ │ ├── EditToolDiffPanel.tsx # Diff preview for edits
|
|
568
|
+
│ │ ├── ErrorMessage.tsx
|
|
569
|
+
│ │ ├── ExpandedPreviewBlock.tsx
|
|
570
|
+
│ │ ├── InputPrompt.tsx # User input
|
|
571
|
+
│ │ ├── MarkdownRenderer.tsx
|
|
572
|
+
│ │ ├── ProgressBar.tsx
|
|
573
|
+
│ │ ├── ReasoningDisplay.tsx # LLM reasoning
|
|
574
|
+
│ │ ├── SessionStats.tsx
|
|
575
|
+
│ │ ├── SimpleDiff.tsx
|
|
576
|
+
│ │ ├── SlashCommands.tsx # 20+ commands
|
|
577
|
+
│ │ ├── StatusNotification.tsx
|
|
578
|
+
│ │ ├── StreamingText.tsx # Live text output
|
|
579
|
+
│ │ ├── TodoPlanDisplay.tsx # Task visualization
|
|
580
|
+
│ │ ├── ToolCallDisplay.tsx
|
|
581
|
+
│ │ ├── ToolResultCard.tsx # Structured results
|
|
582
|
+
│ │ ├── ToolResultDisplay.tsx
|
|
583
|
+
│ │ ├── TypewriterText.tsx
|
|
584
|
+
│ │ ├── UpdateNotice.tsx
|
|
585
|
+
│ │ └── toolCallRenderers.tsx
|
|
586
|
+
│ ├── theme/ # Terminal theming
|
|
587
|
+
│ └── utils/ # UI utilities
|
|
588
|
+
├── main.ts # Entry point
|
|
589
|
+
└── types/ # Global types
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
---
|
|
593
|
+
|
|
594
|
+
## Testing
|
|
1037
595
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
→ Agent reads file with read_file_lines
|
|
1042
|
-
→ Plans changes with todo
|
|
1043
|
-
→ Applies edits with edit_tool (shows preview)
|
|
1044
|
-
→ Runs tests with shell_command
|
|
1045
|
-
→ Reports results
|
|
596
|
+
```bash
|
|
597
|
+
npm test # Run all tests
|
|
598
|
+
npm run test:watch # Watch mode
|
|
1046
599
|
```
|
|
1047
600
|
|
|
1048
|
-
|
|
1049
|
-
```
|
|
1050
|
-
User: "Commit my changes"
|
|
1051
|
-
→ Agent loads git-commit skill
|
|
1052
|
-
→ Runs git status --short
|
|
1053
|
-
→ Stages files with git add
|
|
1054
|
-
→ Writes conventional commit message
|
|
1055
|
-
→ Executes git commit
|
|
1056
|
-
```
|
|
601
|
+
### Test Structure
|
|
1057
602
|
|
|
1058
|
-
**11. Data Analysis & Reporting**
|
|
1059
603
|
```
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
604
|
+
tests/ # 33 test files (flat structure)
|
|
605
|
+
├── agent_*.spec.ts # Agent routing, overlays, coordination
|
|
606
|
+
├── edit_tool.spec.ts # File editing operations
|
|
607
|
+
├── file_write.spec.ts # File write operations
|
|
608
|
+
├── sandbox_policy.spec.ts # Tool execution policies
|
|
609
|
+
├── task_runtime.integration.spec.ts # Task lifecycle
|
|
610
|
+
├── context_compression.integration.spec.ts # Context management
|
|
611
|
+
├── hook_registry.spec.ts # Hook system and event tracking
|
|
612
|
+
├── plugin_registry.spec.ts # Plugin loading and lifecycle
|
|
613
|
+
├── session_registry.spec.ts # Session management
|
|
614
|
+
├── session_manager.spec.ts # Session lifecycle
|
|
615
|
+
├── tool_execution_policy.spec.ts # Safe vs dangerous tool decisions
|
|
616
|
+
├── diagnostics.spec.ts # System diagnostics
|
|
617
|
+
├── runtime_config.spec.ts # Runtime configuration
|
|
618
|
+
├── slash_routing.spec.ts # Slash command routing
|
|
619
|
+
├── subagents_flow.integration.spec.ts # Subagent coordination
|
|
620
|
+
├── prompt_builder.spec.ts # Prompt engineering
|
|
621
|
+
├── token_counter.spec.ts # Token counting
|
|
622
|
+
├── coding_memory.spec.ts # Persistent memory
|
|
623
|
+
├── web_fetch.spec.ts # Web fetching
|
|
624
|
+
├── workspace_snapshot.spec.ts # Workspace analysis
|
|
625
|
+
├── ui_*.spec.ts(x) # UI component tests
|
|
626
|
+
└── ... # Additional integration and unit tests
|
|
1066
627
|
```
|
|
1067
628
|
|
|
1068
629
|
---
|
|
1069
630
|
|
|
1070
|
-
##
|
|
1071
|
-
We welcome contributions! For full details, read [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
1072
|
-
|
|
1073
|
-
### 📋 Prerequisites
|
|
1074
|
-
- **Node.js** >= 18 and **npm** >= 9 installed
|
|
1075
|
-
- Dependencies installed via `npm install`
|
|
1076
|
-
- Required environment variables configured (see *Configuration* section)
|
|
1077
|
-
|
|
1078
|
-
### 🔄 Contribution Workflow
|
|
1079
|
-
1. **Fork** the repository
|
|
1080
|
-
2. **Clone** your fork locally
|
|
1081
|
-
3. Create a feature branch named according to [Conventional Commits](https://www.conventionalcommits.org/) (e.g., `feat/add-logging`)
|
|
1082
|
-
4. Commit changes with meaningful messages
|
|
1083
|
-
5. Push to your fork and open a Pull Request
|
|
1084
|
-
|
|
1085
|
-
### 🛠 Code Standards
|
|
1086
|
-
- Follow TypeScript strict mode guidelines
|
|
1087
|
-
- Maintain style via ESLint and Prettier (`npm run lint`)
|
|
1088
|
-
- Keep functions short, modular, and documented with JSDoc
|
|
1089
|
-
- All business logic must have unit tests
|
|
1090
|
-
|
|
1091
|
-
### 🧪 Testing Requirements
|
|
1092
|
-
- Run `npm test` and ensure all tests pass
|
|
1093
|
-
- Include new tests for any new functionality or bug fix
|
|
1094
|
-
- Validate integration tests when adding new tools or APIs
|
|
1095
|
-
|
|
1096
|
-
### 🔍 Code Review Process
|
|
1097
|
-
- Minimum of 1 maintainer approval before merge
|
|
1098
|
-
- Resolve all review comments and passing CI before merge
|
|
1099
|
-
|
|
1100
|
-
### 📄 Documentation
|
|
1101
|
-
- Update README.md or relevant Wiki pages when adding/removing features
|
|
1102
|
-
- Add or update CHANGELOG.md for notable changes
|
|
1103
|
-
|
|
1104
|
-
---
|
|
1105
|
-
|
|
1106
|
-
## Coding memory
|
|
1107
|
-
|
|
1108
|
-
BluMa includes a **persistent coding memory** system that stores notes about the codebase, decisions, and context that survive across sessions:
|
|
1109
|
-
|
|
1110
|
-
- Memory is stored in `~/.bluma/coding_memory.json`
|
|
1111
|
-
- Use the `coding_memory` tool to **add**, **list**, **search**, **update** (by id), or **remove** (one id at a time). There is **no** bulk “clear all” action.
|
|
1112
|
-
- Notes can be tagged for easy categorization (e.g., `['api', 'auth', 'performance']`)
|
|
1113
|
-
- Memory is loaded at session start and can be searched during tasks
|
|
1114
|
-
|
|
1115
|
-
### When to use Coding Memory:
|
|
1116
|
-
- After learning stable facts about architecture or conventions
|
|
1117
|
-
- To store important URLs, API endpoints, or design decisions
|
|
1118
|
-
- To remember user preferences that should persist across sessions
|
|
1119
|
-
- To document invariants or critical system behaviors
|
|
1120
|
-
|
|
1121
|
-
### Example:
|
|
1122
|
-
```json
|
|
1123
|
-
{
|
|
1124
|
-
"action": "add",
|
|
1125
|
-
"note": "Project uses FactorRouter for LLM routing with model auto-selection",
|
|
1126
|
-
"tags": ["llm", "architecture"]
|
|
1127
|
-
}
|
|
1128
|
-
```
|
|
1129
|
-
|
|
1130
|
-
---
|
|
631
|
+
## Contributing
|
|
1131
632
|
|
|
1132
|
-
|
|
1133
|
-
- Logging verbosity could be made configurable.
|
|
1134
|
-
- Potential for richer plugin lifecycle (install/remove at runtime).
|
|
1135
|
-
- Improve error reporting in subagents.
|
|
1136
|
-
- Expand skill library with more domain-specific modules.
|
|
633
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
1137
634
|
|
|
1138
|
-
|
|
635
|
+
### Quick Contribution Guide
|
|
1139
636
|
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
- **Input Validation:** All user inputs are validated and sanitized to prevent prompt injection attacks.
|
|
637
|
+
1. **Fork** the repository
|
|
638
|
+
2. Create a branch: `feat/add-feature` or `fix/bug-description`
|
|
639
|
+
3. Make changes following the style guide
|
|
640
|
+
4. Add/update tests
|
|
641
|
+
5. Ensure build passes: `npm run build && npm test`
|
|
642
|
+
6. Open a Pull Request
|
|
1147
643
|
|
|
1148
|
-
|
|
644
|
+
### Style Guide
|
|
1149
645
|
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
-
|
|
1153
|
-
-
|
|
1154
|
-
- **Tool Execution Errors**: Displayed with detailed message; execution can be retried or skipped.
|
|
1155
|
-
- **LLM/API Exceptions**: Fall back to safe mode and keep context intact.
|
|
1156
|
-
- **Session/History Save Failures**: Warn user and continue without losing core functionality.
|
|
646
|
+
- Use **English** for code, comments, and commits
|
|
647
|
+
- 2-space indentation
|
|
648
|
+
- TypeScript with modern React patterns
|
|
649
|
+
- Follow existing code structure
|
|
1157
650
|
|
|
1158
651
|
---
|
|
1159
652
|
|
|
1160
|
-
##
|
|
1161
|
-
- **Performance Metrics**: Average response time, tokens used per request, tool execution times.
|
|
1162
|
-
- **Usage Tracking**: Number of commands executed, tool calls, sessions created.
|
|
1163
|
-
- **Logging**: Structured logs for all events.
|
|
1164
|
-
- Integration-ready with Prometheus/Grafana or external observability platforms.
|
|
653
|
+
## License
|
|
1165
654
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
## 🔐 Advanced Security Practices
|
|
1169
|
-
- Use secret management tools (Vault, AWS Secrets Manager) to store environment variables.
|
|
1170
|
-
- Apply principle of least privilege for API keys.
|
|
1171
|
-
- Validate and sanitize all user inputs to avoid prompt injection attacks.
|
|
1172
|
-
- Regularly rotate API keys.
|
|
655
|
+
Apache 2.0 — see [LICENSE](LICENSE) for details.
|
|
1173
656
|
|
|
1174
657
|
---
|
|
1175
658
|
|
|
1176
|
-
##
|
|
1177
|
-
- Optimize context window by pruning irrelevant history.
|
|
1178
|
-
- Batch related operations to reduce LLM calls.
|
|
1179
|
-
- Support for distributed execution or remote agent hosting.
|
|
1180
|
-
- Cache static responses where possible.
|
|
659
|
+
## Support
|
|
1181
660
|
|
|
1182
|
-
|
|
661
|
+
- **Issues**: [GitHub Issues](https://github.com/nomad-e/bluma-cli/issues)
|
|
662
|
+
- **Documentation**: This README + `docs/` directory
|
|
663
|
+
- **Author**: Alex Fonseca
|
|
664
|
+
- **npm Package**: [@nomad-e/bluma-cli](https://www.npmjs.com/package/@nomad-e/bluma-cli)
|
|
1183
665
|
|
|
1184
|
-
|
|
1185
|
-
- **Testing**: `npm test` and `npm run test:watch` for development.
|
|
1186
|
-
- **Linting**: Enforce coding standards with ESLint/Prettier.
|
|
1187
|
-
- **CI/CD**: Recommended GitHub Actions or similar to run tests/build on push.
|
|
1188
|
-
- **Deployment**: Automatic packaging to npm or internal registry.
|
|
666
|
+
### Runtime Modules (v0.1.41+)
|
|
1189
667
|
|
|
1190
|
-
|
|
668
|
+
BluMa's runtime layer provides enterprise-grade orchestration:
|
|
1191
669
|
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
670
|
+
| Module | Purpose | Key Features |
|
|
671
|
+
|--------|---------|--------------|
|
|
672
|
+
| `task_store.ts` | Task lifecycle | PLANNING → EXECUTION → VERIFICATION phases, persistence |
|
|
673
|
+
| `hook_registry.ts` | Event system | Tool calls, decisions, state changes |
|
|
674
|
+
| `plugin_registry.ts` | Plugin system | Load from `.bluma/plugins/`, lifecycle management |
|
|
675
|
+
| `session_registry.ts` | Multi-session | Process health monitoring, session isolation |
|
|
676
|
+
| `sandbox_policy.ts` | Safety | Safe vs dangerous tool classification |
|
|
677
|
+
| `tool_execution_policy.ts` | Execution rules | Auto-approve, confirm, block decisions |
|
|
678
|
+
| `diagnostics.ts` | System snapshots | Tasks, hooks, plugins, sessions overview |
|
|
679
|
+
| `session_view.ts` | Session monitoring | Log streaming, status display |
|
|
680
|
+
| `native_tool_catalog.ts` | Tool registry | Discovery and metadata |
|
|
681
|
+
| `runtime_config.ts` | Settings | Runtime configuration management |
|
|
1197
682
|
|
|
1198
|
-
|
|
1199
|
-
- Follow [CHANGELOG.md](CHANGELOG.md) for version history.
|
|
683
|
+
### UI Components
|
|
1200
684
|
|
|
1201
|
-
|
|
685
|
+
Key UI components that power the rich terminal experience:
|
|
1202
686
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
-
|
|
1206
|
-
|
|
687
|
+
| Component | Purpose |
|
|
688
|
+
|-----------|---------|
|
|
689
|
+
| `EditToolDiffPanel.tsx` | Side-by-side diff previews before edits |
|
|
690
|
+
| `ToolResultCard.tsx` | Structured tool output display |
|
|
691
|
+
| `SlashCommands.tsx` | Command palette and help |
|
|
692
|
+
| `StreamingText.tsx` | Live text output with typing effects |
|
|
693
|
+
| `ReasoningDisplay.tsx` | LLM reasoning visualization |
|
|
694
|
+
| `TodoPlanDisplay.tsx` | Task list visualization |
|
|
695
|
+
| `SessionStats.tsx` | Session metrics and status |
|
|
696
|
+
| `AnimatedBorder.tsx` | Visual feedback for active elements |
|
|
697
|
+
| `CollapsibleResult.tsx` | Expandable result sections |
|
|
698
|
+
| `ProgressBar.tsx` | Progress indicators |
|
|
1207
699
|
|
|
1208
700
|
---
|
|
1209
701
|
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
- Keep functions short, modular and documented.
|
|
1214
|
-
- Add unit tests for all business logic.
|
|
1215
|
-
|
|
1216
|
-
---
|
|
702
|
+
<p align="center">
|
|
703
|
+
<sub>Built with ❤️ by NomadEngenuity</sub>
|
|
704
|
+
</p>
|