@asobacloud/nehanda 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/LICENSE.md +57 -0
- package/README.md +444 -2
- package/bin/agent.mjs +1260 -0
- package/bin/nehanda-ui.mjs +824 -0
- package/lib/anthropicHeaders.mjs +8 -0
- package/lib/app.mjs +313 -0
- package/lib/auth.mjs +255 -0
- package/lib/bashguard.mjs +159 -0
- package/lib/compact.mjs +306 -0
- package/lib/energy-middleware.mjs +318 -0
- package/lib/hookShapeOrder.mjs +30 -0
- package/lib/hookplane.mjs +228 -0
- package/lib/instructions.mjs +23 -0
- package/lib/jev_read.mjs +216 -0
- package/lib/jev_write.mjs +253 -0
- package/lib/laya.mjs +296 -0
- package/lib/laya_sidecar.mjs +198 -0
- package/lib/mcp-config.mjs +189 -0
- package/lib/mcp.mjs +169 -0
- package/lib/modelConfig.mjs +152 -0
- package/lib/modelDiscovery.mjs +205 -0
- package/lib/openaiCompat.mjs +147 -0
- package/lib/orchestrate.mjs +1163 -0
- package/lib/paths.mjs +20 -0
- package/lib/permissions.mjs +44 -0
- package/lib/scripts/__pycache__/laya_worker.cpython-314.pyc +0 -0
- package/lib/scripts/audit-code-integrity.py +437 -0
- package/lib/scripts/ensure-laya-env.sh +55 -0
- package/lib/scripts/js-safety-checker.cjs +308 -0
- package/lib/scripts/laya_worker.py +171 -0
- package/lib/scripts/odse-transform.py +97 -0
- package/lib/scripts/python-safety-checker.py +197 -0
- package/lib/scripts/shell-safety-checker.sh +306 -0
- package/lib/settings.mjs +147 -0
- package/lib/store.mjs +278 -0
- package/lib/team.mjs +69 -0
- package/lib/testgen.mjs +146 -0
- package/lib/tools/AuditCodeIntegrity.json +30 -0
- package/lib/tools/JsSafetyChecker.json +29 -0
- package/lib/tools/PythonSafetyChecker.json +29 -0
- package/lib/tools/ShellSafetyChecker.json +29 -0
- package/lib/tools.mjs +907 -0
- package/lib/transcript.mjs +223 -0
- package/lib/ui.mjs +286 -0
- package/lib/workflow.mjs +91 -0
- package/lib/worktree.mjs +56 -0
- package/package.json +50 -4
- package/schema.sql +181 -0
- package/scripts/postinstall.mjs +62 -0
- package/scripts/sdlc-acceptance.sh +477 -0
- package/scripts/verify-sdlc-hook-order.mjs +26 -0
- package/templates/test_e2e.sh +32 -0
- package/templates/test_file.sh +14 -0
- package/templates/test_hook.sh +27 -0
- package/templates/test_http.sh +17 -0
- package/templates/test_phase.sh +23 -0
- package/templates/test_process.sh +14 -0
- package/templates/test_tool.sh +24 -0
- package/templates/validate_test.sh +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Asoba Corp
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# License
|
|
2
|
+
|
|
3
|
+
**SPDX-Identifier:** `AGPL-3.0-only`
|
|
4
|
+
|
|
5
|
+
Copyright (C) 2026 Asoba Corporation
|
|
6
|
+
|
|
7
|
+
nehanda-cli is free software: you may redistribute it and/or modify it under the
|
|
8
|
+
terms of the [GNU Affero General Public License v3.0](https://www.gnu.org/licenses/agpl-3.0.html)
|
|
9
|
+
or (at your option) any later version.
|
|
10
|
+
|
|
11
|
+
The full license text is maintained verbatim in the [LICENSE](LICENSE) file at the
|
|
12
|
+
repository root. A copy is also available from the Free Software Foundation at
|
|
13
|
+
<https://www.gnu.org/licenses/agpl-3.0.txt>.
|
|
14
|
+
|
|
15
|
+
## What this covers
|
|
16
|
+
|
|
17
|
+
This license applies to **nehanda-cli** — the open-source client and local server
|
|
18
|
+
stack in this repository, including:
|
|
19
|
+
|
|
20
|
+
- `nehanda`, `nehanda-server`, and `nehanda-kb` binaries built from this tree
|
|
21
|
+
- Nehanda-specific code under `src/`
|
|
22
|
+
- Patches under `patches/` and the `upstream/` aimee subtree as distributed here
|
|
23
|
+
- Documentation, configuration examples, and install scripts in this repository
|
|
24
|
+
|
|
25
|
+
If you modify nehanda-cli and make it available to users over a network, AGPL-3.0
|
|
26
|
+
requires you to provide corresponding source to those users. See Section 13 of the
|
|
27
|
+
AGPL for the network-use provision.
|
|
28
|
+
|
|
29
|
+
## AGPL boundary
|
|
30
|
+
|
|
31
|
+
nehanda-cli is designed so that proprietary services communicate over standard HTTP
|
|
32
|
+
using the OpenAI/Anthropic wire protocol. The following are **not** part of this
|
|
33
|
+
repository and are **not** licensed under AGPL-3.0:
|
|
34
|
+
|
|
35
|
+
- Nehanda Gateway (HTTPS proxy in front of the inference endpoint)
|
|
36
|
+
- Nehanda model weights and fine-tune data
|
|
37
|
+
- Hosted inference at `nehanda.asoba.co`
|
|
38
|
+
- ONA/Zorora auth services (`ona-user-auth`, `ona-platform-users`, device pairing)
|
|
39
|
+
|
|
40
|
+
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the three-tier design and where
|
|
41
|
+
the AGPL line sits.
|
|
42
|
+
|
|
43
|
+
## Upstream — aimee
|
|
44
|
+
|
|
45
|
+
nehanda-cli is a fork of [aimee](https://github.com/RakuenSoftware/aimee), Copyright
|
|
46
|
+
(C) 2026 The aimee authors, also licensed under AGPL-3.0. Upstream source is
|
|
47
|
+
tracked as a git subtree under `upstream/`. Nehanda-specific changes live in `src/`
|
|
48
|
+
and `patches/`.
|
|
49
|
+
|
|
50
|
+
## Third-party components
|
|
51
|
+
|
|
52
|
+
Third-party licenses inherited from aimee and vendored dependencies are listed in
|
|
53
|
+
[NOTICE](NOTICE), including cJSON (MIT) and build-time tree-sitter grammars (MIT).
|
|
54
|
+
|
|
55
|
+
## Questions
|
|
56
|
+
|
|
57
|
+
For licensing questions about nehanda-cli, contact **support@asoba.co**.
|
package/README.md
CHANGED
|
@@ -1,3 +1,445 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Nehanda Command-Line Interface (`nehanda-cli`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An agentic terminal REPL and single-process engine built for governed AI deep research and software development. `nehanda-cli` connects directly to our flagship [Nehanda v3](https://huggingface.co/asoba/nehanda-v3-27b), as well as local or cloud-based Ollama models, LM Studio instances, or any OpenAI-compatible API.
|
|
4
|
+
|
|
5
|
+
Every conversation turn, tool call, phase transition, and permission check is stored in a local, queryable SQLite database you own, ensuring complete transcripts exist for auditing and debugging.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Getting Started
|
|
12
|
+
|
|
13
|
+
### Requirements
|
|
14
|
+
|
|
15
|
+
* **Node.js**: v22.0.0 or higher
|
|
16
|
+
* **Python**: 3.10 or higher (for the Laya System-1 control plane)
|
|
17
|
+
* **SQLite**: Local SQLite runtime support
|
|
18
|
+
|
|
19
|
+
### 1. Installation
|
|
20
|
+
|
|
21
|
+
**Global install (recommended):**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install -g @asobacloud/nehanda
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
During install, `npm` automatically provisions a dedicated Python venv and downloads the [Laya](https://huggingface.co/convaiinnovations/laya) checkpoint (~808 MB). This happens once — subsequent starts are instant.
|
|
28
|
+
|
|
29
|
+
**From source:**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git clone https://github.com/AsobaCloud/nehanda-cli.git
|
|
33
|
+
cd nehanda-cli
|
|
34
|
+
npm install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The same one-time provisioning runs automatically as part of `npm install`.
|
|
38
|
+
|
|
39
|
+
### 2. Launching the REPL
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
nehanda
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or via the aliases installed with the package:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
ona
|
|
49
|
+
ona-code
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3. Provider Setup
|
|
53
|
+
|
|
54
|
+
#### Option A: Nehanda Cloud (Default)
|
|
55
|
+
|
|
56
|
+
The CLI defaults to the primary Nehanda endpoint (`https://nehanda-ml.asoba.co/v1`). If an API key is required:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
❯ /key
|
|
60
|
+
New Nehanda API key: <your-key>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### Option B: Local LM Studio
|
|
64
|
+
|
|
65
|
+
Start LM Studio locally on port `1234` or `8000`, then start the CLI. Select or switch models via:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
❯ /model
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### Option C: Remote Ollama over LAN
|
|
72
|
+
|
|
73
|
+
To connect to an Ollama instance running on your network:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
❯ /config base_url http://AsobaCorp-1.local:11434/v1
|
|
77
|
+
❯ /model ollama/deepseek-coder-v2:latest
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Key Features
|
|
83
|
+
|
|
84
|
+
* **In-Process Engine:** Executes turns directly inside the process via `runUserTurn`, eliminating separate server daemons or background HTTP relays.
|
|
85
|
+
|
|
86
|
+
* **Jev-Mem Memory Architecture:** Every turn, a System-1 control plane ([Laya](https://huggingface.co/convaiinnovations/laya)) classifies observations into a multi-relational memory graph (semantic / temporal / causal / entity edges), then adaptively retrieves evidence before each model call. System-2 receives a compact canonical header + retrieved evidence + last 2 turns, not a raw transcript — cutting prefill 70–85% on long sessions. See [Jev-Mem Architecture](#jev-mem-architecture) below.
|
|
87
|
+
|
|
88
|
+
* **Dynamic Tool Rescue (`[TOOL_CALL]`):** Native support for endpoints that strip OpenAI tool schemas (such as `nehandaMlProxy`). The engine dynamically injects active tool schemas directly into system prompts as `[TOOL_CALL]` blocks, parsing and executing tools locally without server-side function-calling support. Uses `[TOOL_CALL]` delimiters instead of `<tool_call>` XML to prevent vLLM's `--tool-call-parser qwen3_xml` stop-token interception.
|
|
89
|
+
|
|
90
|
+
* **Deterministic SDLC Workflow:** Enforces a 6-phase state machine (`idle` → `plan` → `implement` → `test` → `verify` → `done`) to prevent unapproved code changes, hallucinated test passes, or unverified implementations.
|
|
91
|
+
|
|
92
|
+
* **Interactive TUI & Pipe Support:** Rich Ink-based TUI (`bin/nehanda-ui.mjs`) for interactive development sessions, with headless pipe-mode support (`bin/agent.mjs`) for acceptance testing and automation.
|
|
93
|
+
|
|
94
|
+
* **Multi-Provider Switching:** Seamlessly switch between Nehanda 27B, local LM Studio, Ollama instances over LAN, Anthropic Claude, or any OpenAI-compatible API using `/model`.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Architecture
|
|
99
|
+
|
|
100
|
+
`nehanda-cli` combines an Ink TUI with a deterministic orchestration engine:
|
|
101
|
+
|
|
102
|
+

|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Jev-Mem Architecture
|
|
107
|
+
|
|
108
|
+
`nehanda-cli` implements the memory architecture from **"System-One-Controlled Agentic Memory for Efficient AI Agents"** (Jiang, Li & Li, UT Dallas — [arXiv:2609.23986](https://arxiv.org/abs/2609.23986)). The core insight: the frequent, structured decisions of memory management — typing, relation judgment, retrieval routing, sufficiency assessment — don't need an autoregressive LLM. They need a fast, calibrated System-1 model.
|
|
109
|
+
|
|
110
|
+
The System-1 control plane is [**Laya**](https://huggingface.co/convaiinnovations/laya) — a 421M-parameter, non-autoregressive decision model (open weights, Apache 2.0) that answers typed questions in a single forward pass (~33 ms on GPU, ~200 ms on CPU). It never generates text, so there is nothing to parse and nothing to hallucinate.
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
Observation (user / tool / assistant turn)
|
|
114
|
+
│
|
|
115
|
+
▼
|
|
116
|
+
┌── WRITE PATH (System 1 — Laya) ───────────────────────────────┐
|
|
117
|
+
│ type scores: episodic / semantic / procedural / preference │
|
|
118
|
+
│ → deterministic TopK candidates (FTS + entities + recency) │
|
|
119
|
+
│ → Laya relation judgments (semantic/causal/episode/entity) │
|
|
120
|
+
│ → insert edges iff P(relation) ≥ θ_rel │
|
|
121
|
+
│ → update laya_jev_state (task_status, file_target, escalate) │
|
|
122
|
+
└───────────────────────────────────────────────────────────────┘
|
|
123
|
+
│
|
|
124
|
+
▼ SQLite memory plane
|
|
125
|
+
nodes + edges (semantic | temporal | causal | entity)
|
|
126
|
+
+ FTS/lexical index
|
|
127
|
+
│
|
|
128
|
+
▼
|
|
129
|
+
┌── READ PATH (System 1 — Laya) ────────────────────────────────┐
|
|
130
|
+
│ route: which graph views matter for this query │
|
|
131
|
+
│ → RRF anchors (FTS + recency) │
|
|
132
|
+
│ → assess sufficiency / utility / contradiction │
|
|
133
|
+
│ → expand under budget → rescore → stop │
|
|
134
|
+
└───────────────────────────────────────────────────────────────┘
|
|
135
|
+
│
|
|
136
|
+
▼
|
|
137
|
+
┌── SYSTEM 2 PROMPT ────────────────────────────────────────────┐
|
|
138
|
+
│ [CANONICAL SYSTEM 1 STATE] (task_status, file_target, ...) │
|
|
139
|
+
│ [RETRIEVED EVIDENCE] (top-K memories, not raw transcript) │
|
|
140
|
+
│ last 2 turns + last failed tool result │
|
|
141
|
+
└───────────────────────────────────────────────────────────────┘
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Paper invariants preserved
|
|
145
|
+
|
|
146
|
+
- Observations are always persisted on ingest — nothing is dropped on write.
|
|
147
|
+
- Candidate discovery is deterministic (FTS + recency) before any Laya relation judgments.
|
|
148
|
+
- Temporal and entity edges are derived from structure where possible; Laya is invoked only when needed.
|
|
149
|
+
- Retrieval is a closed loop: route → retrieve → assess → expand → reassess → stop on sufficiency.
|
|
150
|
+
- System-2 only synthesizes; it does not route, score, or stop the retrieval loop.
|
|
151
|
+
|
|
152
|
+
### Laya: the System-1 model
|
|
153
|
+
|
|
154
|
+
| | |
|
|
155
|
+
|---|---|
|
|
156
|
+
| Weights | [convaiinnovations/laya](https://huggingface.co/convaiinnovations/laya) — Apache 2.0, open weights |
|
|
157
|
+
| Size | 421M parameters (ModernBERT-large backbone + decision head) |
|
|
158
|
+
| Latency | ~33 ms / question on GPU; ~200 ms on CPU (MPS on Apple Silicon) |
|
|
159
|
+
| Training | RLCD — reinforcement learning against strictly proper scoring rules; honest probabilities are the only way to maximise reward |
|
|
160
|
+
| Question types | `noul` (probability), `choice` (categorical), `score` (ordinal) |
|
|
161
|
+
| Languages | English checkpoint (root); `laya-multilingual` covers 100+ languages |
|
|
162
|
+
|
|
163
|
+
On first startup, `lib/scripts/ensure-laya-env.sh` creates a dedicated venv at `~/.nehanda/venv` and downloads the checkpoint. The sidecar is then warmed before the first turn so all subsequent predictions hit the hot path. If provisioning fails, the CLI exits with a clear error — Laya is not an optional feature.
|
|
164
|
+
|
|
165
|
+
### Memory plane (SQLite)
|
|
166
|
+
|
|
167
|
+
The memory plane extends the existing `memories` table and adds `memory_edges` and `laya_jev_state`. All data lives in the same local SQLite database as the rest of the session state (`~/.config/nehanda/ona-session.db`).
|
|
168
|
+
|
|
169
|
+
| Table | Purpose |
|
|
170
|
+
|---|---|
|
|
171
|
+
| `memories` | Canonical node store — one row per observation, with overlapping type scores (episodic / semantic / procedural / preference), entity tags, and provenance |
|
|
172
|
+
| `memories_fts` | FTS5 index over memory content for lexical anchor retrieval |
|
|
173
|
+
| `memory_edges` | Multi-relational edges — same node pair may have independent semantic, temporal, causal, and entity edges |
|
|
174
|
+
| `laya_jev_state` | Session control block: `task_status`, `file_target`, `escalation_risk`, `confidence_score` |
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Tool Calling Architecture
|
|
179
|
+
|
|
180
|
+
The Nehanda vLLM deployment runs with `--tool-call-parser qwen3_xml` and `--enable-auto-tool-choice` flags. The `nehandaMlProxy` Lambda function strips `tools` and `tool_choice` from requests before forwarding to vLLM to avoid a Qwen3 chat template bug where the presence of a `tools` array causes system message ordering errors.
|
|
181
|
+
|
|
182
|
+
To enable tool calling despite this constraint, the engine uses a rescue path:
|
|
183
|
+
|
|
184
|
+
1. **System Prompt Injection:** `buildXmlToolInstructions()` injects tool schemas into the system prompt using `[TOOL_CALL]...[/TOOL_CALL]` delimiters.
|
|
185
|
+
2. **Late Directive Injection:** A `[SYSTEM DIRECTIVE]` is appended to the final user message to defeat token recency bias on reasoning models.
|
|
186
|
+
3. **Model Generation:** The model emits tool calls in the `[TOOL_CALL]` format within its response text.
|
|
187
|
+
4. **Local Parsing & Execution:** `parseXmlToolCalls()` extracts and executes these calls locally via `executeBuiltinTool()`, continuing the execution loop even when backends return `finish_reason: "stop"`.
|
|
188
|
+
|
|
189
|
+
### Why `[TOOL_CALL]` Delimiters?
|
|
190
|
+
|
|
191
|
+
The vLLM `--tool-call-parser qwen3_xml` flag registers `<tool_call>` XML tags as stop/intercept tokens. When the model emits them in plain text, vLLM terminates generation mid-sentence and hands off to its native parser — which returns nothing because the plain-text path never populates `message.tool_calls`. This results in truncated responses containing only thinking traces.
|
|
192
|
+
|
|
193
|
+
Switching to `[TOOL_CALL]...[/TOOL_CALL]` delimiters bypasses vLLM's stop-token interception entirely, allowing the model to complete generation and return valid, parseable tool calls.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Declarative Tool System
|
|
198
|
+
|
|
199
|
+
`nehanda-cli` supports a **zero-code tool configuration** pattern. Tools are registered by dropping a JSON config into `lib/tools/` and a corresponding script into `lib/scripts/`. No JavaScript changes are required.
|
|
200
|
+
|
|
201
|
+
### How It Works
|
|
202
|
+
|
|
203
|
+
1. On startup, `lib/tools.mjs` scans `lib/tools/*.json` and dynamically registers each tool.
|
|
204
|
+
2. Tool schemas are injected into the API `tools` array so the model can call them.
|
|
205
|
+
3. Phase visibility (`explore_only`, `planning_blocked`) and mandatory enforcement (`mandatory_in`) are driven by config metadata.
|
|
206
|
+
4. Prompt injection (`prompt.mandatory_instruction`, `prompt.available_hint`) is read from the config and injected into the appropriate SDLC phase system prompts automatically.
|
|
207
|
+
|
|
208
|
+
### Shipped Tools
|
|
209
|
+
|
|
210
|
+
| Tool | Script | What It Checks |
|
|
211
|
+
|---|---|---|
|
|
212
|
+
| `AuditCodeIntegrity` | `lib/scripts/audit-code-integrity.py` | Lifecycle teardown parity, mock-theater tests, naming invariants, swallowed exceptions |
|
|
213
|
+
| `ShellSafetyChecker` | `lib/scripts/shell-safety-checker.sh` | Missing `set -euo pipefail`, background job silent failure risk, hardcoded credentials |
|
|
214
|
+
| `JsSafetyChecker` | `lib/scripts/js-safety-checker.cjs` | Duplicate functions, duplicate HTML element IDs, script block syntax errors |
|
|
215
|
+
| `PythonSafetyChecker` | `lib/scripts/python-safety-checker.py` | Bandit security issues, ruff lint, mutable default args, `eval`/`exec`/`pickle` usage |
|
|
216
|
+
|
|
217
|
+
All four are **mandatory in the test phase** and **available on-demand** in explore and idle phases.
|
|
218
|
+
|
|
219
|
+
### Adding a New Tool
|
|
220
|
+
|
|
221
|
+
Create a JSON config in `lib/tools/`:
|
|
222
|
+
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"name": "MyNewTool",
|
|
226
|
+
"description": "What the tool does.",
|
|
227
|
+
"input_schema": {
|
|
228
|
+
"type": "object",
|
|
229
|
+
"properties": {
|
|
230
|
+
"target": { "type": "string", "description": "Target path" }
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
"phases": {
|
|
234
|
+
"explore_only": true,
|
|
235
|
+
"planning_blocked": false,
|
|
236
|
+
"mandatory_in": ["test"]
|
|
237
|
+
},
|
|
238
|
+
"prompt": {
|
|
239
|
+
"mandatory_instruction": "Run MyNewTool on the workspace to check for X.",
|
|
240
|
+
"available_hint": "Checks for X, Y, and Z"
|
|
241
|
+
},
|
|
242
|
+
"execution": {
|
|
243
|
+
"runtime": "python3",
|
|
244
|
+
"script": "lib/scripts/my-new-tool.py",
|
|
245
|
+
"args": ["{{target}}"],
|
|
246
|
+
"default_timeout": 120000,
|
|
247
|
+
"max_timeout": 600000
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Place the script at `lib/scripts/my-new-tool.py`. It will receive arguments interpolated from `args` and run with `cwd` set to the target workspace. **No JS code changes needed.**
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## REPL Commands
|
|
257
|
+
|
|
258
|
+
| Command | Description |
|
|
259
|
+
|---|---|
|
|
260
|
+
| `/help` | Display available commands |
|
|
261
|
+
| `/model [name]` | Discover and switch active provider or model endpoint |
|
|
262
|
+
| `/key` | Save Nehanda API key |
|
|
263
|
+
| `/config` | View or set settings (e.g., `/config base_url <url>`) |
|
|
264
|
+
| `/mcp` | Manage MCP server connections (see below) |
|
|
265
|
+
| `/clear` | Clear conversation history and reset transcript state |
|
|
266
|
+
| `/retry` | Resend the last failed request |
|
|
267
|
+
| `/exit` | Exit the REPL |
|
|
268
|
+
|
|
269
|
+
### `/mcp` Sub-commands
|
|
270
|
+
|
|
271
|
+
| Sub-command | Description |
|
|
272
|
+
|---|---|
|
|
273
|
+
| `/mcp status` | List all configured MCP servers and their commands |
|
|
274
|
+
| `/mcp list` | Connect to each server and enumerate available tools |
|
|
275
|
+
| `/mcp reload [server]` | Re-read `mcp.json` and bust the tool cache (optionally for one server) |
|
|
276
|
+
| `/mcp add <name> <command> [args…]` | Register a new server and save it to `~/.config/nehanda/mcp.json` |
|
|
277
|
+
| `/mcp env` | Show environment variables for all configured servers |
|
|
278
|
+
| `/mcp env <server>` | Show environment variables for a specific server |
|
|
279
|
+
| `/mcp env <server> <KEY> <value>` | Set an environment variable (e.g. an API key) |
|
|
280
|
+
| `/mcp env <server> <KEY>` | Clear an environment variable |
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## MCP Client Configuration
|
|
285
|
+
|
|
286
|
+
`nehanda-cli` can consume tools from any external MCP server. Servers are configured in a standard `mcp.json` file using the same schema as Claude Desktop and other MCP clients.
|
|
287
|
+
|
|
288
|
+
**Config file locations** (both are read and merged at startup; project-local takes priority):
|
|
289
|
+
|
|
290
|
+
- `./mcp.json` — project-local, committed with the repo
|
|
291
|
+
- `~/.config/nehanda/mcp.json` — user global
|
|
292
|
+
|
|
293
|
+
**Example `mcp.json`:**
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"mcpServers": {
|
|
298
|
+
"filesystem": {
|
|
299
|
+
"command": "npx",
|
|
300
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
|
|
301
|
+
},
|
|
302
|
+
"powermcp": {
|
|
303
|
+
"command": "npx",
|
|
304
|
+
"args": ["-y", "harvard-powermcp"],
|
|
305
|
+
"env": { "API_KEY": "your-key" }
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
At startup, `nehanda-cli` loads `mcp.json`, spawns the configured servers, and calls `tools/list` on each. Discovered tools are injected into the model's tool list under the namespace `mcp__<server>__<tool>` and are available for the model to call during any conversation turn — no additional configuration required.
|
|
312
|
+
|
|
313
|
+
Use `/mcp list` to verify what tools are visible, and `/mcp reload` to pick up changes without restarting.
|
|
314
|
+
|
|
315
|
+
### Setting API Keys for MCP Servers
|
|
316
|
+
|
|
317
|
+
Many MCP servers require an API key or other secrets. Rather than editing `mcp.json` by hand, use the `/mcp env` command directly from the REPL:
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
❯ /mcp env # show env vars for all servers
|
|
321
|
+
❯ /mcp env asoba # show env vars for 'asoba' server
|
|
322
|
+
❯ /mcp env asoba ASOBA_API_KEY sk-abc123... # set the key
|
|
323
|
+
✓ Set ASOBA_API_KEY = ******** on asoba
|
|
324
|
+
Config file: ~/.config/nehanda/mcp.json
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
This writes the value to the `mcp.json` file where the server is defined (project-local `./mcp.json` takes priority over global `~/.config/nehanda/mcp.json`), then automatically reloads the server so the change takes effect immediately.
|
|
328
|
+
|
|
329
|
+
To clear a key:
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
❯ /mcp env asoba ASOBA_API_KEY
|
|
333
|
+
✓ Cleared ASOBA_API_KEY on asoba
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Tip:** Keys are masked in `/mcp env` output. Only the first 6 and last 4 characters are shown.
|
|
337
|
+
|
|
338
|
+
#### Connecting to JupyterLab
|
|
339
|
+
|
|
340
|
+
`mcp.json` ships with a `jupyter` server pre-configured pointing at `localhost:8888`. To connect it to your JupyterLab instance:
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
❯ /mcp env jupyter JUPYTER_URL http://my-server:8888
|
|
344
|
+
❯ /mcp env jupyter JUPYTER_TOKEN <your-token>
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Both values are written to `~/.config/nehanda/mcp.json` and never committed. The server reloads automatically.
|
|
348
|
+
|
|
349
|
+
### General Config from the REPL
|
|
350
|
+
|
|
351
|
+
Use `/config set <dot.path> <value>` to set any configuration value without editing files:
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
❯ /config set model_config.base_url https://api.anthropic.com
|
|
355
|
+
❯ /config set model_config.num_ctx 8192
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Numeric values are auto-converted. Changes persist in the local settings database.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## SDLC Workflow
|
|
363
|
+
|
|
364
|
+
The engine enforces state transitions across six distinct phases:
|
|
365
|
+
|
|
366
|
+
1. **`idle`**: Discovery and triage. Mutating file tools are physically masked out. Safety and analysis tools are available on-demand.
|
|
367
|
+
|
|
368
|
+
2. **`plan`**: Model formulates success criteria and implementation steps (`EnterPlanMode`). No tools available.
|
|
369
|
+
|
|
370
|
+
3. **`implement`**: Code changes applied using file editing and shell execution (`ExitPlanMode`).
|
|
371
|
+
|
|
372
|
+
4. **`test`**: Automated test generation and execution (`SubmitImplementation`). **After tests pass, all tools marked `mandatory_in: ["test"]` must be run.** The system prompt enforces this — the model cannot declare success until all mandatory safety checkers pass.
|
|
373
|
+
|
|
374
|
+
5. **`verify`**: Inspection of test outputs and coverage verification (`SubmitTest`).
|
|
375
|
+
|
|
376
|
+
6. **`done`**: Final sign-off and git commit creation.
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## Database Schema
|
|
381
|
+
|
|
382
|
+
Session state is persisted locally at `~/.config/nehanda/ona-session.db`. Key tables include:
|
|
383
|
+
|
|
384
|
+
* `conversations`: Active workflow phases and project roots.
|
|
385
|
+
* `transcript_entries`: Sequence of user messages, assistant turns, tool calls, and results.
|
|
386
|
+
* `plans`: Content, hashes, and approval status for technical plans.
|
|
387
|
+
* `events`: SDLC milestones and test execution output.
|
|
388
|
+
* `memories`: Jev-Mem canonical node store with overlapping type scores and entity provenance.
|
|
389
|
+
* `memory_edges`: Multi-relational graph edges (semantic / temporal / causal / entity).
|
|
390
|
+
* `laya_jev_state`: System-1 session control block (task_status, file_target, escalation_risk).
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Testing & Verification
|
|
395
|
+
|
|
396
|
+
Run the acceptance suite:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
npm run acceptance
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Verify SDLC hook ordering:
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
npm run verify
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Run the Jev-Mem behavioral suite directly:
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
node tests/unit/jev_write_behavioral.mjs
|
|
412
|
+
node tests/unit/jev_read_behavioral.mjs
|
|
413
|
+
node tests/unit/compact_jev_behavioral.mjs
|
|
414
|
+
node tests/unit/orchestrate_jev_hotpath_behavioral.mjs
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## Changelog
|
|
420
|
+
|
|
421
|
+
### 0.3.0
|
|
422
|
+
- Published as `@asobacloud/nehanda` on npm — install with `npm install -g @asobacloud/nehanda`
|
|
423
|
+
- Laya System-1 venv provisioning moved to `npm install` time via `scripts/postinstall.mjs` — CLI starts instantly on every subsequent launch
|
|
424
|
+
- Laya provisioning now streams live pip progress to the terminal instead of running silently
|
|
425
|
+
- Added project-local `mcp.json` with `datalayer/jupyter-mcp-server` preconfigured for JupyterLab — set your server URL and token with `/mcp env jupyter JUPYTER_URL <url>` and `/mcp env jupyter JUPYTER_TOKEN <token>`
|
|
426
|
+
|
|
427
|
+
### 0.2.0
|
|
428
|
+
- Jev-Mem memory architecture (System-1 Laya control plane)
|
|
429
|
+
- Dynamic Tool Rescue (`[TOOL_CALL]` delimiter path)
|
|
430
|
+
- Deterministic 6-phase SDLC workflow
|
|
431
|
+
- Multi-provider switching
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## References
|
|
436
|
+
|
|
437
|
+
Jiang, Z., Li, Y., & Li, J. (2026). *System-One-Controlled Agentic Memory for Efficient AI Agents*. arXiv:2609.23986. https://arxiv.org/abs/2609.23986
|
|
438
|
+
|
|
439
|
+
Convai Innovations. *Laya: Multilingual, non-autoregressive System-1 decision model.* Hugging Face. https://huggingface.co/convaiinnovations/laya
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## License
|
|
444
|
+
|
|
445
|
+
See [LICENSE](LICENSE) for details.
|