@slenderbuilds/niti 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +155 -0
- package/bin/niti-core.js +7 -0
- package/bin/niti.js +6 -0
- package/bin/resolve.js +32 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shubhadeep Datta
|
|
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/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# niti
|
|
2
|
+
|
|
3
|
+
**A terminal CLI that runs multiple AI coding agents — from different LLM providers — concurrently on one project.**
|
|
4
|
+
|
|
5
|
+
Assign models to custom roles (Gemini = Frontend, Claude = Backend, GPT = Reviewer...), pick one as the **orchestrator** to plan the work into a task DAG, and watch the team build together, **talking to each other directly** to stay aligned — live in your terminal, or in an optional web dashboard.
|
|
6
|
+
|
|
7
|
+
[](#license)
|
|
8
|
+
[](#two-front-ends-one-core)
|
|
9
|
+
[](#two-front-ends-one-core)
|
|
10
|
+
|
|
11
|
+
<img src="readme_images/CLI.png" alt="niti's terminal UI — team of 4 agents, live context/token sidebar" width="100%">
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install -g @slenderbuilds/niti # prebuilt binaries — no Bun, no Go, no build step
|
|
17
|
+
niti # pick your team, then start building
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
> Published as **`@slenderbuilds/niti`** — the unscoped `niti` was rejected by npm's own
|
|
21
|
+
> anti-squatting check (too similar to `jiti`/`vite`/others), and it suggested this scope. The
|
|
22
|
+
> commands are still `niti` (TUI) and `niti-core` (headless engine); project state still lives
|
|
23
|
+
> in `.niti/` — only the install name changed.
|
|
24
|
+
|
|
25
|
+
On first launch, `niti` opens a picker: how many teammates (1–6), then per teammate — provider,
|
|
26
|
+
model, name, and a one-line job description. **29 providers / 152 models** from the
|
|
27
|
+
[Models.dev](https://models.dev) catalog, plus local (Ollama/LM Studio) and **Custom** for any
|
|
28
|
+
OpenAI-compatible endpoint. Keys live in `~/.config/niti/auth.json` (0600) and your OS keychain —
|
|
29
|
+
never a server.
|
|
30
|
+
|
|
31
|
+
Type `/` for the full command list:
|
|
32
|
+
|
|
33
|
+
<img src="readme_images/commands.png" alt="the / command palette, listing every slash command" width="100%">
|
|
34
|
+
|
|
35
|
+
## Watch it from the browser too
|
|
36
|
+
|
|
37
|
+
`/dashboard` opens a live control center — agent avatars, message graph, task board, and per-agent
|
|
38
|
+
usage, all pushed over SSE as the team works:
|
|
39
|
+
|
|
40
|
+
<img src="readme_images/dashboardniti.png" alt="the web dashboard — live agent graph with task/message/usage panels" width="100%">
|
|
41
|
+
|
|
42
|
+
`/graph` opens an interactive force-graph — your project's file/import structure, or (toggle to
|
|
43
|
+
**Models**) the live agent-to-agent conversation as it happens:
|
|
44
|
+
|
|
45
|
+
<table>
|
|
46
|
+
<tr>
|
|
47
|
+
<td width="50%"><img src="readme_images/graph1.png" alt="project mode: 137-file dependency graph"></td>
|
|
48
|
+
<td width="50%"><img src="readme_images/graph2.png" alt="models mode: live pixel-art agent avatars, message-colored edges"></td>
|
|
49
|
+
</tr>
|
|
50
|
+
<tr>
|
|
51
|
+
<td>Project mode — every file, colored by directory</td>
|
|
52
|
+
<td>Models mode — your team, colored by status, talking in real time</td>
|
|
53
|
+
</tr>
|
|
54
|
+
</table>
|
|
55
|
+
|
|
56
|
+
Both pages retheme live with whatever theme (`ctrl+t` / `/theme`) the TUI has active.
|
|
57
|
+
|
|
58
|
+
## Everything, at a glance
|
|
59
|
+
|
|
60
|
+
`/settings` (or `tab`) opens Status, Config, Usage, and Stats panes without leaving the session:
|
|
61
|
+
|
|
62
|
+
<table>
|
|
63
|
+
<tr>
|
|
64
|
+
<td width="33%"><img src="readme_images/status.png" alt="Status tab — version, team, mode, theme, models"></td>
|
|
65
|
+
<td width="33%"><img src="readme_images/usage.png" alt="Usage tab — session cost, tokens, per-agent breakdown"></td>
|
|
66
|
+
<td width="34%"><img src="readme_images/stats_models.png" alt="Stats tab — tokens per day, tokens by model"></td>
|
|
67
|
+
</tr>
|
|
68
|
+
</table>
|
|
69
|
+
|
|
70
|
+
## What's actually happening under the hood
|
|
71
|
+
|
|
72
|
+
- **Orchestrator DAG** — the lead agent turns your goal into a validated task graph (dependencies +
|
|
73
|
+
hand-offs), not a flat queue; independent tasks run concurrently and the lead reviews at the end.
|
|
74
|
+
- **Agent-to-agent messaging** — any teammate can `ask_agent`/`send_message` another mid-task (e.g.
|
|
75
|
+
frontend asking backend about an API shape), rate-capped per pair as the loop guard.
|
|
76
|
+
- **Sandboxed tools** — `read_file` / `write_file` / `edit` / `shell`, gated per-agent by
|
|
77
|
+
`allowedTools` and a wildcard permission policy; every path is jailed to the project root.
|
|
78
|
+
- **Approval gates** — agents pause for `[y] approve · [n] deny · [a] always` before risky actions,
|
|
79
|
+
answered from the TUI or the web dashboard; dangerous shell patterns always prompt.
|
|
80
|
+
- **Persistence** — every turn checkpoints to SQLite (`.niti/niti.db`); `niti-core resume` picks up
|
|
81
|
+
unfinished tasks with history intact. `/undo` and `/rewind` revert file writes.
|
|
82
|
+
- **MCP + LSP** — declare `mcpServers`/`lsp` in `agents.yaml`; both merge into the same tool loop,
|
|
83
|
+
gated the same way as everything else.
|
|
84
|
+
- **Failover** — a 429/overload/context-limit requeues the task instead of failing it; another agent
|
|
85
|
+
picks it up.
|
|
86
|
+
|
|
87
|
+
See [`project_context.md`](./project_context.md) for the full architecture record, the verification
|
|
88
|
+
history, and the deliberate ceilings (what's intentionally out of scope, and why).
|
|
89
|
+
|
|
90
|
+
## Configuring agents
|
|
91
|
+
|
|
92
|
+
`niti` rewrites only the `agents:` block on each team pick — everything else survives a relaunch.
|
|
93
|
+
Edit `.niti/agents.yaml` directly for anything the picker doesn't cover:
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
agents:
|
|
97
|
+
- id: architect
|
|
98
|
+
provider: anthropic
|
|
99
|
+
model: claude-opus-4-8
|
|
100
|
+
role: Architect
|
|
101
|
+
lead: true
|
|
102
|
+
systemPrompt: You are a software architect. Decompose work into independent subtasks.
|
|
103
|
+
- id: engineer
|
|
104
|
+
provider: openai
|
|
105
|
+
model: gpt-4o
|
|
106
|
+
role: Backend Engineer
|
|
107
|
+
systemPrompt: You are a backend engineer. Implement the assigned task.
|
|
108
|
+
allowedTools: [read_file, write_file, edit, shell, mcp]
|
|
109
|
+
|
|
110
|
+
permissions:
|
|
111
|
+
shell: { "git *": allow, "git commit *": ask, "rm -rf*": deny }
|
|
112
|
+
write_file: { "src/**": allow, "*": ask }
|
|
113
|
+
|
|
114
|
+
mcpServers:
|
|
115
|
+
- name: code-review
|
|
116
|
+
command: code-review-graph
|
|
117
|
+
args: [--stdio]
|
|
118
|
+
|
|
119
|
+
theme: niti # ctrl+t / /theme opens a live carousel, synced to any open dashboard/graph tab
|
|
120
|
+
auto: false # approve anything not explicitly denied
|
|
121
|
+
maxAgents: 6
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Full config reference — permissions resolution order, environment variables, LSP setup — lives in
|
|
125
|
+
[`project_context.md`](./project_context.md).
|
|
126
|
+
|
|
127
|
+
## From source
|
|
128
|
+
|
|
129
|
+
Requires [Bun](https://bun.sh) ≥ 1.3 and [Go](https://go.dev) ≥ 1.22.
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
bun install
|
|
133
|
+
bun run build:tui # builds ./niti (the Go TUI)
|
|
134
|
+
./niti
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Headless / scripting, no interactive terminal needed:
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
bun run src/cli.ts "Build a clothing website for gen-z." # one-shot
|
|
141
|
+
bun run src/cli.ts --web "..." # + live web dashboard
|
|
142
|
+
bun run src/server/main.ts # headless server, prints its own handshake URL
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Development
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
bun test # TypeScript unit + integration tests
|
|
149
|
+
bunx tsc --noEmit # typecheck
|
|
150
|
+
cd tui && go build ./... && go vet ./... && go test ./... # Go TUI: build, vet, unit tests
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT.
|
package/bin/niti-core.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The headless engine/scripting CLI (`niti-core "task"`, `serve`, `auth`, …). Same handover as
|
|
3
|
+
// bin/niti.js — the TUI spawns this binary directly as a sibling, without going through Node.
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { binPath } from "./resolve.js";
|
|
6
|
+
|
|
7
|
+
process.exit(spawnSync(binPath("niti-core"), process.argv.slice(2), { stdio: "inherit" }).status ?? 1);
|
package/bin/niti.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The interactive TUI. Node runs this shim; everything after the handover is Go and Bun.
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { binPath } from "./resolve.js";
|
|
5
|
+
|
|
6
|
+
process.exit(spawnSync(binPath("niti"), process.argv.slice(2), { stdio: "inherit" }).status ?? 1);
|
package/bin/resolve.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
// This package ships no binaries. The real executables live in per-platform packages
|
|
6
|
+
// (`niti-darwin-arm64`, …) declared as optionalDependencies with `os`/`cpu` set, so npm installs
|
|
7
|
+
// exactly the one that matches and skips the other four.
|
|
8
|
+
//
|
|
9
|
+
// PLATFORM_BASE is deliberately NOT derived from this package's own `name`: the root wrapper is
|
|
10
|
+
// published as a scoped package (`@slenderbuilds/niti`, npm's own suggestion — the unscoped `niti`
|
|
11
|
+
// collided with its squatting-prevention check against jiti/vite/nib/…), but the five platform
|
|
12
|
+
// packages are unscoped (`niti-darwin-arm64`, …) and were already published under that name before
|
|
13
|
+
// the scope existed. `${name}-${platform}` would have produced `@slenderbuilds/niti-darwin-arm64`,
|
|
14
|
+
// which is not a real package — see scripts/build-release.ts, which publishes under this same
|
|
15
|
+
// hardcoded base.
|
|
16
|
+
const PLATFORM_BASE = "niti";
|
|
17
|
+
|
|
18
|
+
export function binPath(exe) {
|
|
19
|
+
const platformPkg = `${PLATFORM_BASE}-${process.platform}-${process.arch}`;
|
|
20
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
21
|
+
try {
|
|
22
|
+
return require.resolve(`${platformPkg}/bin/${exe}${ext}`);
|
|
23
|
+
} catch {
|
|
24
|
+
console.error(
|
|
25
|
+
`niti: no prebuilt binary for ${process.platform}-${process.arch} (looked for ${platformPkg}).\n` +
|
|
26
|
+
`Supported: darwin-arm64, darwin-x64, linux-x64, linux-arm64, win32-x64.\n` +
|
|
27
|
+
`If your platform is on that list, reinstall — npm sometimes skips optional dependencies ` +
|
|
28
|
+
`(https://github.com/npm/cli/issues/4828).`,
|
|
29
|
+
);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@slenderbuilds/niti",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A terminal CLI that runs multiple AI coding agents from different LLM providers concurrently on one project.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"niti": "bin/niti.js",
|
|
8
|
+
"niti-core": "bin/niti-core.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin/",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"dev": "bun run src/cli.ts",
|
|
17
|
+
"serve": "bun run src/server/main.ts",
|
|
18
|
+
"build": "bun build --compile ./src/cli.ts --outfile niti-core",
|
|
19
|
+
"build:tui": "cd tui && go mod tidy && go build -o ../niti ./cmd/niti",
|
|
20
|
+
"build:all": "bun run build:tui && bun run build",
|
|
21
|
+
"build:release": "bun run scripts/build-release.ts",
|
|
22
|
+
"test": "bun test src web",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"gen:catalog": "bun run scripts/gen-catalog.ts"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/slenderongithub/niti.git"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/slenderongithub/niti#readme",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/slenderongithub/niti/issues"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"ai",
|
|
39
|
+
"agents",
|
|
40
|
+
"cli",
|
|
41
|
+
"tui",
|
|
42
|
+
"llm",
|
|
43
|
+
"coding-agent",
|
|
44
|
+
"multi-agent",
|
|
45
|
+
"anthropic",
|
|
46
|
+
"openai",
|
|
47
|
+
"gemini"
|
|
48
|
+
],
|
|
49
|
+
"author": "Shubhadeep Datta <slenderisincollege@gmail.com>",
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"optionalDependencies": {
|
|
55
|
+
"niti-darwin-arm64": "0.1.0",
|
|
56
|
+
"niti-darwin-x64": "0.1.0",
|
|
57
|
+
"niti-linux-arm64": "0.1.0",
|
|
58
|
+
"niti-linux-x64": "0.1.0",
|
|
59
|
+
"niti-win32-x64": "0.1.0"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@anthropic-ai/sdk": "^0.115.0",
|
|
63
|
+
"@google/genai": "^2.13.0",
|
|
64
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
65
|
+
"@napi-rs/keyring": "^1.3.0",
|
|
66
|
+
"@types/bun": "^1.3.14",
|
|
67
|
+
"openai": "^7.0.0",
|
|
68
|
+
"typescript": "^7.0.2",
|
|
69
|
+
"yaml": "^2.9.0",
|
|
70
|
+
"zod": "^4.4.3"
|
|
71
|
+
}
|
|
72
|
+
}
|