@cmetech/otto 1.0.6 → 1.0.8

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 CHANGED
@@ -1,43 +1,43 @@
1
- <!-- OTTER — the on-laptop coding & research assistant for the otto stack -->
1
+ <!-- OTTO — the on-laptop coding & research assistant -->
2
2
 
3
- # OTTER
3
+ # OTTO
4
4
 
5
- > **O**rchestrating **T**ools, **T**asks, **E**xecution & **R**esearch — call it **OTTO** for short.
5
+ > **O**rchestrating, **T**ools, **T**asks & **O**utcomes
6
6
 
7
- The on-laptop entrypoint for the **otto** stack. A terminal-resident coding, research, and operations assistant for developers, administrators, and project managers — built to keep tool execution local while routing every LLM call through a governable gateway.
7
+ A terminal-resident coding, research, and operations assistant for developers, administrators, and project managers — built to keep tool execution local while routing every LLM call through a governable gateway.
8
8
 
9
- ![OTTER activity flow — OTTER on your laptop, OSCAR on the network](docs/branding/otto_activity_flow_infographic_v3.png)
9
+ ![OTTO activity flow — OTTO on your laptop, OSCAR on the network](docs/branding/otto_activity_flow_infographic_v3.png)
10
10
 
11
11
  ---
12
12
 
13
- ## What OTTER is
13
+ ## What OTTO is
14
14
 
15
- OTTER is the **client CLI** in the otto product family. It is what users actually open in a terminal:
15
+ OTTO is the **client CLI** users open in a terminal:
16
16
 
17
17
  - **One entrypoint for three roles.** A developer asks it to refactor and run tests. An administrator asks it why a node paged last night. A project manager asks it to summarize this week's open tickets. Same CLI, same conversational interface.
18
18
  - **Local execution by default.** Filesystem, bash, git, and tool calls run on the developer's laptop. Nothing leaves the machine unless the task genuinely needs remote data or remote inference.
19
- - **Chat API in, ACP out.** OTTER speaks standard chat-completion APIs (Anthropic / OpenAI / Ollama) to the OTTO Gateway, and REST to a local Langflow. It never speaks raw ACP — the Gateway translates and routes downstream.
20
- - **Compliance-friendly by construction.** When `OTTO_GATEWAY_URL` is set, every LLM token routes through that gateway so governance, audit, and content moderation all live in one place. With no gateway configured, OTTER falls back to direct Anthropic.
19
+ - **Chat API in, ACP out.** OTTO speaks standard chat-completion APIs (Anthropic / OpenAI / Ollama) to the OTTO Gateway, and REST to a local Langflow. It never speaks raw ACP — the Gateway translates and routes downstream.
20
+ - **Compliance-friendly by construction.** When `OTTO_GATEWAY_URL` is set, every LLM token routes through that gateway so governance, audit, and content moderation all live in one place. With no gateway configured, OTTO falls back to direct Anthropic.
21
21
 
22
- OTTER is **not** a general-purpose AI assistant. It is a developer agent that also happens to trigger non-coding workflows through Langflow and reach into operational data through OSCAR.
22
+ OTTO is **not** a general-purpose AI assistant. It is a developer agent that also happens to trigger non-coding workflows through Langflow and reach into operational data through OSCAR.
23
23
 
24
24
  This repo (`@cmetech/otto`, binary `otto`) is the **CLI** piece. The diagram above shows where it sits in the larger stack.
25
25
 
26
26
  ---
27
27
 
28
- ## Where OTTER fits in the otto stack
28
+ ## Where OTTO fits in the stack
29
29
 
30
30
  Everything inside the dashed laptop boundary in the diagram lives on the user's machine. Only OSCAR and the external systems behind it are remote.
31
31
 
32
- | Component | Role | Where it lives | Relationship to OTTER |
32
+ | Component | Role | Where it lives | Relationship to OTTO |
33
33
  |---|---|---|---|
34
- | **OTTER** (this repo) | CLI client + conversation surface | Laptop | The user-facing entrypoint |
35
- | **OTTO Gateway** | Manages all ACP. Translates chat-API requests into ACP calls. Anthropic/OpenAI/Ollama-compatible. Hosts guardrails. | Laptop | OTTER's primary backend — every LLM call lands here first |
36
- | **Langflow** | Low-code flow orchestrator for multi-step automations | Laptop | OTTER calls it via REST when a task is "automate" rather than "ask" |
37
- | **kiro-cli ACP pool** | Pooled subprocess workers under the Gateway | Laptop | Where inference actually executes; OTTER never talks to them directly |
38
- | **OSCAR** | Remote operations agent with an ACP interface. Holds network credentials. Reaches into production servers, lab environments, ticket systems, and knowledge bases. | Remote | Reached only via the Gateway's ACP channel — OTTER never holds ops credentials |
34
+ | **OTTO** (this repo) | CLI client + conversation surface | Laptop | The user-facing entrypoint |
35
+ | **OTTO Gateway** | Manages all ACP. Translates chat-API requests into ACP calls. Anthropic/OpenAI/Ollama-compatible. Hosts guardrails. | Laptop | OTTO's primary backend — every LLM call lands here first |
36
+ | **Langflow** | Low-code flow orchestrator for multi-step automations | Laptop | OTTO calls it via REST when a task is "automate" rather than "ask" |
37
+ | **kiro-cli ACP pool** | Pooled subprocess workers under the Gateway | Laptop | Where inference actually executes; OTTO never talks to them directly |
38
+ | **OSCAR** | Remote operations agent with an ACP interface. Holds network credentials. Reaches into production servers, lab environments, ticket systems, and knowledge bases. | Remote | Reached only via the Gateway's ACP channel — OTTO never holds ops credentials |
39
39
 
40
- The two ACP connections (Gateway ↔ kiro-cli and Gateway ↔ OSCAR) are the load-bearing protocol relationships in the stack. OTTER itself is intentionally protocol-thin.
40
+ The two ACP connections (Gateway ↔ kiro-cli and Gateway ↔ OSCAR) are the load-bearing protocol relationships in the stack. OTTO itself is intentionally protocol-thin.
41
41
 
42
42
  ---
43
43
 
@@ -45,7 +45,7 @@ The two ACP connections (Gateway ↔ kiro-cli and Gateway ↔ OSCAR) are the loa
45
45
 
46
46
  > **The assistant carries the tools. The user keeps the keys.**
47
47
 
48
- OTTER is built around a few non-negotiables:
48
+ OTTO is built around a few non-negotiables:
49
49
 
50
50
  **Local-first.** Tool execution, filesystem access, and developer state stay on the laptop. We don't ship work to a cloud worker when a local one will do.
51
51
 
@@ -53,7 +53,7 @@ OTTER is built around a few non-negotiables:
53
53
 
54
54
  **Extension-first.** New capabilities belong in the `otto` extension, in skills, or in plugins — not in core. The core CLI stays lean. The terminal UI, the flow trigger system, and the prompt engineer all live as extensions.
55
55
 
56
- **Provider-agnostic.** OTTER speaks Anthropic, OpenAI, or Ollama. The Gateway adapts to all three. No architectural decision should privilege one provider over another.
56
+ **Provider-agnostic.** OTTO speaks Anthropic, OpenAI, or Ollama. The Gateway adapts to all three. No architectural decision should privilege one provider over another.
57
57
 
58
58
  **Ship fast, fix fast.** Every release should work, but we'd rather ship and patch than delay and accumulate.
59
59
 
@@ -63,7 +63,7 @@ OTTER is built around a few non-negotiables:
63
63
 
64
64
  ## Status
65
65
 
66
- **v0.x — early release.** The CLI is functional and published to npm. The OTTER brand is being introduced gradually; you will still see `otto` as the package name, binary name, and config-directory name (`~/.otto/`). That is intentional and stable — `otto` is the implementation; OTTER is the product story.
66
+ **v1.x — released.** The CLI is functional and published to npm. The package name, binary name, and config-directory name (`~/.otto/`) all use lowercase `otto`; the product is **OTTO**.
67
67
 
68
68
  ---
69
69
 
@@ -86,7 +86,7 @@ cd otto-cli
86
86
  ./scripts/install.sh
87
87
  ```
88
88
 
89
- The install script installs dependencies, builds the binary, symlinks `otto` into `~/.local/bin/`, and offers to launch the first-run config wizard so you can point OTTER at your gateway and (optionally) at Langflow.
89
+ The install script installs dependencies, builds the binary, symlinks `otto` into `~/.local/bin/`, and offers to launch the first-run config wizard so you can point OTTO at your gateway and (optionally) at Langflow.
90
90
 
91
91
  After install (either path):
92
92
 
@@ -96,13 +96,13 @@ otto --help # subcommands
96
96
  otto config # re-run any part of the config wizard
97
97
  ```
98
98
 
99
- See [`docs/INSTALL.md`](docs/INSTALL.md) for prerequisites, manual install, uninstall, and troubleshooting.
99
+ See [`INSTALL.md`](INSTALL.md) for prerequisites, per-platform setup (Windows/macOS/Linux), and troubleshooting.
100
100
 
101
101
  ---
102
102
 
103
- ## What OTTER can do
103
+ ## What OTTO can do
104
104
 
105
- OTTER classifies each user ask into one of four task types, shown as chips in the diagram above:
105
+ OTTO classifies each user ask into one of four task types, shown as chips in the diagram above:
106
106
 
107
107
  | Chip | What it means | Where it routes |
108
108
  |---|---|---|
@@ -126,7 +126,7 @@ The extension also registers tools for catalog management, component inspection,
126
126
 
127
127
  ## Configuration
128
128
 
129
- OTTER reads from `~/.otto/config.json` (created by the first-run wizard) with env-var overrides:
129
+ OTTO reads from `~/.otto/config.json` (created by the first-run wizard) with env-var overrides:
130
130
 
131
131
  | Env var | Purpose | Default |
132
132
  |---|---|---|
@@ -146,10 +146,10 @@ Env vars always win over the config file. Run `otto config` to interactively set
146
146
 
147
147
  The activity-flow diagram at the top of this README is the canonical picture of how a request becomes an answer. A few things worth calling out for governance reviewers:
148
148
 
149
- 1. **OTTER never speaks ACP.** All inter-agent protocol traffic is handled by the OTTO Gateway. A compromised CLI surface cannot directly issue ACP commands.
150
- 2. **OTTER never holds ops credentials.** Credentials for production servers, ticket systems, and lab environments live with OSCAR (remote). OTTER asks; OSCAR fetches.
149
+ 1. **OTTO never speaks ACP.** All inter-agent protocol traffic is handled by the OTTO Gateway. A compromised CLI surface cannot directly issue ACP commands.
150
+ 2. **OTTO never holds ops credentials.** Credentials for production servers, ticket systems, and lab environments live with OSCAR (remote). OTTO asks; OSCAR fetches.
151
151
  3. **One LLM egress point.** With `OTTO_GATEWAY_URL` set, the laptop has exactly one outbound LLM destination. Audit log, content moderation, rate limiting, and schema validation are configured there, once.
152
- 4. **Local-only requests never leave the laptop.** OTTER classifies "Code" and "Research" asks; many resolve against kiro-cli locally without any network call beyond the laptop boundary.
152
+ 4. **Local-only requests never leave the laptop.** OTTO classifies "Code" and "Research" asks; many resolve against kiro-cli locally without any network call beyond the laptop boundary.
153
153
 
154
154
  The corresponding architecture diagram for the Gateway itself lives in [`docs/branding/otto_architecture_infographic.jpg`](docs/branding/otto_architecture_infographic.jpg). Both diagrams are generated from prompts checked into the same folder.
155
155
 
@@ -157,7 +157,7 @@ The corresponding architecture diagram for the Gateway itself lives in [`docs/br
157
157
 
158
158
  ## Documentation
159
159
 
160
- - [`docs/INSTALL.md`](docs/INSTALL.md) — install / uninstall / troubleshoot
160
+ - [`INSTALL.md`](INSTALL.md) — install / uninstall / troubleshoot
161
161
  - [`docs/user-docs/package-management.md`](docs/user-docs/package-management.md) — install packages that extend OTTO
162
162
  - [`docs/branding/`](docs/branding/) — naming, logo prompts, infographics (activity flow + gateway architecture)
163
163
  - [`docs/superpowers/specs/`](docs/superpowers/specs/) — design specifications
@@ -182,11 +182,11 @@ Plans live in [`docs/superpowers/plans/`](docs/superpowers/plans/) — one per p
182
182
 
183
183
  ## Fork attribution
184
184
 
185
- OTTER (`@cmetech/otto`) is a **permanent hard fork** of [open-gsd/gsd-pi](https://github.com/open-gsd/gsd-pi) by Lex Christopherson, used under the MIT License. The upstream `gsd-pi` provides the agent core, the terminal UI, the extension system, and the multi-step workflow commands. OTTER adds:
185
+ OTTO (`@cmetech/otto`) is a **permanent hard fork** of [open-gsd/gsd-pi](https://github.com/open-gsd/gsd-pi) by Lex Christopherson, used under the MIT License. The upstream `gsd-pi` provides the agent core, the terminal UI, the extension system, and the multi-step workflow commands. OTTO adds:
186
186
 
187
187
  - The `otto` extension (Langflow flow triggers, flow builder, prompt engineer, catalog tools)
188
188
  - Gateway routing for LLM traffic
189
- - OTTER brand identity and terminal UI styling
189
+ - OTTO brand identity and terminal UI styling
190
190
  - Compliance and audit posture
191
191
 
192
192
  See [`LICENSE`](LICENSE) for the full list of fork edits.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmetech/otto",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Terminal-based developer chat assistant. Permanent hard fork of gsd-pi with LangFlow flow triggers, a flow builder, and optional gateway routing for compliance environments.",
5
5
  "keywords": [
6
6
  "ai",
@@ -182,11 +182,11 @@
182
182
  "@anthropic-ai/claude-agent-sdk": "0.2.83",
183
183
  "fsevents": "~2.3.3",
184
184
  "koffi": "^2.9.0",
185
- "@cmetech/otto-engine-darwin-arm64": "1.0.6",
186
- "@cmetech/otto-engine-darwin-x64": "1.0.6",
187
- "@cmetech/otto-engine-linux-arm64-gnu": "1.0.6",
188
- "@cmetech/otto-engine-linux-x64-gnu": "1.0.6",
189
- "@cmetech/otto-engine-win32-x64-msvc": "1.0.6"
185
+ "@cmetech/otto-engine-darwin-arm64": "1.0.8",
186
+ "@cmetech/otto-engine-darwin-x64": "1.0.8",
187
+ "@cmetech/otto-engine-linux-arm64-gnu": "1.0.8",
188
+ "@cmetech/otto-engine-linux-x64-gnu": "1.0.8",
189
+ "@cmetech/otto-engine-win32-x64-msvc": "1.0.8"
190
190
  },
191
191
  "overrides": {
192
192
  "gaxios": "7.1.4",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto-build/contracts",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Shared public contracts for OTTO workspace boundaries",
5
5
  "license": "MIT",
6
6
  "otto": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto-build/daemon",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "OTTO daemon — background process for project monitoring and Discord integration",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@anthropic-ai/sdk": "^0.52.0",
32
- "@otto-build/contracts": "^1.0.6",
33
- "@otto-build/rpc-client": "^1.0.6",
32
+ "@otto-build/contracts": "^1.0.8",
33
+ "@otto-build/rpc-client": "^1.0.8",
34
34
  "discord.js": "^14.25.1",
35
35
  "yaml": "^2.8.0",
36
36
  "zod": "^3.24.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto-build/mcp-server",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "MCP server exposing OTTO orchestration tools for compatible clients",
5
5
  "license": "MIT",
6
6
  "otto": {
@@ -34,8 +34,8 @@
34
34
  "test": "npm run build:test && node --test dist/mcp-server.test.js dist/remote-questions.test.js"
35
35
  },
36
36
  "dependencies": {
37
- "@otto-build/contracts": "^1.0.6",
38
- "@otto-build/rpc-client": "^1.0.6",
37
+ "@otto-build/contracts": "^1.0.8",
38
+ "@otto-build/rpc-client": "^1.0.8",
39
39
  "@modelcontextprotocol/sdk": "^1.27.1",
40
40
  "zod": "^4.0.0"
41
41
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto/native",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Native Rust bindings for OTTO — high-performance native modules via N-API",
5
5
  "type": "commonjs",
6
6
  "otto": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto/pi-agent-core",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "General-purpose agent core (vendored from pi-mono)",
5
5
  "type": "module",
6
6
  "otto": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto/pi-ai",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Unified LLM API (vendored from pi-mono)",
5
5
  "type": "module",
6
6
  "otto": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto/pi-coding-agent",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Coding agent CLI (vendored from pi-mono)",
5
5
  "type": "module",
6
6
  "otto": {
@@ -28,7 +28,7 @@
28
28
  "copy-assets": "node scripts/copy-assets.cjs"
29
29
  },
30
30
  "dependencies": {
31
- "@otto-build/contracts": "^1.0.6",
31
+ "@otto-build/contracts": "^1.0.8",
32
32
  "@mariozechner/jiti": "^2.6.2",
33
33
  "@silvia-odwyer/photon-node": "^0.3.4",
34
34
  "chalk": "^5.5.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto/pi-tui",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Terminal User Interface library (vendored from pi-mono)",
5
5
  "type": "module",
6
6
  "otto": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto-build/rpc-client",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Standalone RPC client SDK for OTTO — zero internal dependencies",
5
5
  "license": "MIT",
6
6
  "otto": {
@@ -34,7 +34,7 @@
34
34
  "test": "node --test dist/rpc-client.test.js"
35
35
  },
36
36
  "dependencies": {
37
- "@otto-build/contracts": "^1.0.6"
37
+ "@otto-build/contracts": "^1.0.8"
38
38
  },
39
39
  "engines": {
40
40
  "node": ">=22.0.0"
package/pkg/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loop24/client",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "piConfig": {
5
5
  "_comment": "AUTO-SYNCED from root package.json by scripts/sync-piconfig.mjs (runs on prebuild). Do not edit this block directly — edit root package.json and re-run `npm run build` or `npm run sync-piconfig`.",
6
6
  "name": "otto",
@@ -15,6 +15,7 @@
15
15
  import { execSync, spawnSync, exec as execCb } from 'child_process'
16
16
  import { createHash, randomUUID } from 'crypto'
17
17
  import { chmodSync, copyFileSync, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'fs'
18
+ import { createRequire } from 'module'
18
19
  import { arch, homedir, platform } from 'os'
19
20
  import { dirname, resolve, join } from 'path'
20
21
  import { Readable } from 'stream'
@@ -486,6 +487,60 @@ function linkWorkspacePackages() {
486
487
  } catch { /* non-fatal */ }
487
488
  }
488
489
 
490
+ // ── Step: Copy bundled tools (ripgrep, fd) into ~/.otto/bin/ ───────────────
491
+
492
+ function copyBundledTools() {
493
+ // The @cmetech/otto-engine-* package matching this platform contains rg/fd
494
+ // alongside otto_engine.node. Copy them into ~/.otto/bin/ so the runtime
495
+ // tools-manager finds them at the expected location with no GitHub download.
496
+ const platMap = {
497
+ 'darwin-arm64': 'darwin-arm64',
498
+ 'darwin-x64': 'darwin-x64',
499
+ 'linux-x64': 'linux-x64-gnu',
500
+ 'linux-arm64': 'linux-arm64-gnu',
501
+ 'win32-x64': 'win32-x64-msvc',
502
+ }
503
+ const key = `${platform()}-${arch()}`
504
+ const suffix = platMap[key]
505
+ if (!suffix) return // unsupported platform — nothing to bundle
506
+
507
+ const nativePkgName = `@cmetech/otto-engine-${suffix}`
508
+ let nativePkgDir
509
+ try {
510
+ const req = createRequire(import.meta.url)
511
+ const pkgJsonPath = req.resolve(`${nativePkgName}/package.json`, { paths: [packageRoot] })
512
+ nativePkgDir = dirname(pkgJsonPath)
513
+ } catch {
514
+ // Native package not installed — optionalDep didn't match (unsupported platform)
515
+ return
516
+ }
517
+
518
+ const binExt = platform() === 'win32' ? '.exe' : ''
519
+ // Must match getBinDir() in packages/pi-coding-agent/src/config.ts:
520
+ // join(getAgentDir(), 'bin') where getAgentDir() is ~/.otto/agent/.
521
+ // If config.ts ever moves the agent dir, update both spots together.
522
+ const dest = join(homedir(), '.otto', 'agent', 'bin')
523
+ mkdirSync(dest, { recursive: true })
524
+
525
+ const tools = ['rg', 'fd']
526
+ const copied = []
527
+ for (const tool of tools) {
528
+ const src = join(nativePkgDir, `${tool}${binExt}`)
529
+ const dst = join(dest, `${tool}${binExt}`)
530
+ if (existsSync(src)) {
531
+ copyFileSync(src, dst)
532
+ if (platform() !== 'win32') {
533
+ chmodSync(dst, 0o755)
534
+ }
535
+ copied.push(tool)
536
+ }
537
+ }
538
+
539
+ if (copied.length > 0) {
540
+ printStep('Bundled tools', `${copied.join(' + ')} copied to ~/.otto/agent/bin/`)
541
+ }
542
+ }
543
+
489
544
  // ── Step: Verify installation ──────────────────────────────────────────────
490
545
 
491
546
  function verifyInstall(local) {
@@ -536,6 +591,7 @@ const isLocal = args.includes('--local') || args.includes('-l')
536
591
  if (IS_POSTINSTALL) {
537
592
  // Running as npm postinstall hook — just do workspace linking + deps
538
593
  linkWorkspacePackages()
594
+ copyBundledTools()
539
595
  await installChromium()
540
596
  await installRtk()
541
597
  } else {
@@ -550,6 +606,7 @@ if (IS_POSTINSTALL) {
550
606
 
551
607
  // Run postinstall steps that npm skipped
552
608
  linkWorkspacePackages()
609
+ copyBundledTools()
553
610
  await installChromium()
554
611
  await installRtk()
555
612