@charzhu/openjaw-agent 0.2.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 +546 -0
- package/config.yaml +72 -0
- package/dist/main.js +61348 -0
- package/dist/main.js.map +7 -0
- package/package.json +134 -0
- package/prompts/COMPUTER_USE.md +87 -0
- package/prompts/IDENTITY.md +33 -0
- package/prompts/REASONING.md +182 -0
- package/prompts/SAFETY.md +43 -0
- package/prompts/USER.md +37 -0
- package/skills/competitive-battlecard.md +98 -0
- package/skills/create-docx.md +174 -0
- package/skills/create-pdf-report.md +93 -0
- package/skills/create-pptx.md +109 -0
- package/skills/daily-briefing.md +65 -0
- package/skills/data-analysis.md +127 -0
- package/skills/deep-research.md +101 -0
- package/skills/desktop-cleanup.md +82 -0
- package/skills/doc-coauthoring.md +123 -0
- package/skills/email-drafting.md +141 -0
- package/skills/email-with-attachment.md +114 -0
- package/skills/internal-comms.md +88 -0
- package/skills/meeting-summarizer.md +72 -0
- package/skills/proofreading.md +77 -0
- package/skills/refresh-token.md +161 -0
- package/skills/skill-creator.md +122 -0
- package/skills/summarization.md +110 -0
- package/skills/translation.md +94 -0
- package/skills/web-research.md +93 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 charzhu
|
|
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,546 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>🤖 OpenJaw Agent</h1>
|
|
3
|
+
<p><b>Autonomous Desktop AI Assistant — multi-provider, multi-channel, config-driven.</b></p>
|
|
4
|
+
<p>Runs independently in your terminal. No MCP server, no Claude Code, no Copilot CLI required.</p>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What is OpenJaw Agent?
|
|
10
|
+
|
|
11
|
+
OpenJaw Agent is a **standalone AI assistant** that runs in your Windows terminal and can automate your entire desktop:
|
|
12
|
+
|
|
13
|
+
- 📧 **Email** — Read, compose, reply, forward, search (Outlook via COM)
|
|
14
|
+
- 💬 **Teams** — Send messages, read chats, monitor conversations (UIA automation)
|
|
15
|
+
- 💬 **WeChat** — Send messages, read chats via official iLink Bot API
|
|
16
|
+
- 🌐 **Browser** — Navigate, click, type, screenshot, extract content (Chrome CDP)
|
|
17
|
+
- 📄 **Office** — Word, Excel, PowerPoint automation (COM)
|
|
18
|
+
- 📁 **Files** — Read, write, edit, search, list, delete
|
|
19
|
+
- 🖥️ **System** — Run commands, clipboard, notifications, web search
|
|
20
|
+
- 🧠 **Memory** — Persistent hybrid-search memory, shared with MCP mode
|
|
21
|
+
- 🔌 **MCP** — Auto-discovers and connects to external MCP servers
|
|
22
|
+
- 🗣️ **Voice** — Text-to-speech (edge-tts) and speech-to-text input
|
|
23
|
+
- 🎓 **Skills** — 19 bundled skills for email drafting, research, document creation, and more
|
|
24
|
+
|
|
25
|
+
It connects to **Claude** or **GPT** via your proxy or API key, reasons about your request, picks the right tools, and executes them autonomously.
|
|
26
|
+
|
|
27
|
+
### Multi-Channel Access
|
|
28
|
+
|
|
29
|
+
Beyond the terminal, the agent can be accessed through messaging bridges — all running the same agent loop with full tool access:
|
|
30
|
+
|
|
31
|
+
| Channel | Flag | How It Works |
|
|
32
|
+
|---------|------|-------------|
|
|
33
|
+
| **Terminal** | _(default)_ | New TUI built on React + vendored `@openjaw/ink`, with streaming, status bars, tool progress, and model/session controls |
|
|
34
|
+
| **Telegram** | `--telegram` | Long-polling bot — text, voice, photos. No public IP needed |
|
|
35
|
+
| **Telegram headless** | `--telegram --headless` | Telegram-only, no terminal UI |
|
|
36
|
+
| **Teams** | `--teams` | Self-chat bridge via Graph API. No bot registration needed |
|
|
37
|
+
| **Feishu (Lark)** | `--feishu` | WebSocket events via official SDK |
|
|
38
|
+
| **WeChat** | `--wechat` | iLink Bot API — QR login from iOS WeChat |
|
|
39
|
+
| **Legacy Ink UI** | `--legacy-ui` | Previous Ink UI (pre-rewrite) for A/B comparison |
|
|
40
|
+
| **Legacy REPL** | `--legacy` | Simple readline REPL |
|
|
41
|
+
|
|
42
|
+
Bridges run alongside the terminal UI (hybrid mode) or standalone (headless).
|
|
43
|
+
|
|
44
|
+
### Terminal UI Architecture
|
|
45
|
+
|
|
46
|
+
The default terminal experience is the new TUI rewrite. `src/bootstrap.ts` initializes the in-process `AgentLoop`, tools, MCP, memory, voice, and bridge services; `src/eventBridge.ts` translates agent chunks into typed `GatewayEvent` objects; and `src/agentBus.ts` exposes a hermes-compatible `GatewayClient` event/RPC bus. `src/rpcHandlers.ts` serves the ported hermes hooks (`useMainApp`, `useSessionLifecycle`, `useSubmission`, and related hooks), while nanostores under `src/app/*` hold UI state for turns, overlays, selections, and delegation. React components in `src/components/*` render through the vendored `@openjaw/ink` renderer, a fork of hermes ink; see `packages/openjaw-ink/VENDOR.md` for provenance.
|
|
47
|
+
|
|
48
|
+
Use the default command for the new TUI, `--legacy-ui` to A/B test against the previous Ink UI, or `--legacy` for the readline REPL. See [`docs/TUI.md`](docs/TUI.md) for a concise map of the UI rewrite.
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
### Prerequisites
|
|
53
|
+
|
|
54
|
+
- **Node.js 18+** — [Download](https://nodejs.org)
|
|
55
|
+
- **Windows 10/11** recommended (some automation tools require Windows; cross-platform basics work elsewhere)
|
|
56
|
+
- **LLM access** — Maestro proxy, Anthropic/OpenAI API keys, or GitHub Copilot via `/connect`
|
|
57
|
+
|
|
58
|
+
### Install from npm (recommended)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Global install — exposes the `openjaw-agent` command on PATH
|
|
62
|
+
npm install -g @charzhu/openjaw-agent
|
|
63
|
+
openjaw-agent
|
|
64
|
+
|
|
65
|
+
# Or run on demand without installing
|
|
66
|
+
npx @charzhu/openjaw-agent
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The package ships a single bundled `dist/main.js` (no postinstall build step). After install, run `/connect` to pick a provider, then `/model` to pick a model.
|
|
70
|
+
|
|
71
|
+
### Install from source (for contributors)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git clone https://github.com/charzhu/openjaw.git
|
|
75
|
+
cd openjaw/openjaw-agent
|
|
76
|
+
|
|
77
|
+
# One-click install (builds openjaw core + agent, configures proxy)
|
|
78
|
+
install.bat
|
|
79
|
+
|
|
80
|
+
# Or manually:
|
|
81
|
+
cd ../openjaw-mcp && npm install && npm run build # build core first
|
|
82
|
+
cd ../openjaw-agent && npm install && npm run build
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Configure
|
|
86
|
+
|
|
87
|
+
For normal interactive use, you do not need to edit provider keys in YAML. Launch OpenJaw Agent, run `/connect` to pick Maestro, Anthropic, OpenAI, or GitHub Copilot, then run `/model` to choose from connected providers. `/connect` stores direct provider credentials in `~/.openjaw-agent/auth.json` and each provider context starts with a sensible default model.
|
|
88
|
+
|
|
89
|
+
`config.yaml` in the package directory, or `~/.openjaw-agent/config.yaml` after first run, is mainly for advanced defaults and non-interactive deployments:
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
llm:
|
|
93
|
+
provider: anthropic # updated by /connect
|
|
94
|
+
model: claude-sonnet-4-20250514 # updated by /model
|
|
95
|
+
api_key: proxy-token # placeholder; direct keys are stored by /connect
|
|
96
|
+
base_url: http://localhost:23333/api/anthropic # default Maestro proxy URL
|
|
97
|
+
max_tokens: 16384
|
|
98
|
+
temperature: 0.7
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Advanced OpenAI-compatible proxy tuning is still available with `openai_tool_mode: auto | compact | full` and `openai_max_tools`, but it is not part of the normal setup flow.
|
|
102
|
+
|
|
103
|
+
<details>
|
|
104
|
+
<summary>OpenAI configuration example</summary>
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
llm:
|
|
108
|
+
provider: openai
|
|
109
|
+
model: gpt-5.4
|
|
110
|
+
api_key: proxy-token # actual key is read from ~/.openjaw-agent/auth.json
|
|
111
|
+
max_tokens: 16384
|
|
112
|
+
temperature: 0.7
|
|
113
|
+
```
|
|
114
|
+
</details>
|
|
115
|
+
|
|
116
|
+
For local proxy mode through Agent Maestro (`http://localhost:23333/api/anthropic` or `http://localhost:23333/api/openai`), use `/connect maestro`, then `/model` to choose a Maestro model. Maestro model selections use the local proxy and do not use Anthropic/OpenAI API keys stored by `/connect`. For OpenAI-compatible proxy requests, the default `openai_tool_mode: auto` sends a compact subset of tools instead of the full registry. All tools remain executable locally; the model can request additional tools with `openjaw_load_tools`. Use `openai_tool_mode: full` only for endpoints that reliably handle the full tool inventory.
|
|
117
|
+
|
|
118
|
+
<details>
|
|
119
|
+
<summary>Anthropic direct (no proxy) example</summary>
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
llm:
|
|
123
|
+
provider: anthropic
|
|
124
|
+
model: claude-sonnet-4-20250514
|
|
125
|
+
api_key: proxy-token # actual key is read from ~/.openjaw-agent/auth.json
|
|
126
|
+
max_tokens: 16384
|
|
127
|
+
temperature: 0.7
|
|
128
|
+
```
|
|
129
|
+
</details>
|
|
130
|
+
|
|
131
|
+
<details>
|
|
132
|
+
<summary>Telegram bridge configuration</summary>
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
telegram:
|
|
136
|
+
token: "YOUR_BOT_TOKEN" # Get from @BotFather
|
|
137
|
+
allowed_users: [YOUR_USER_ID] # Get from @userinfobot
|
|
138
|
+
```
|
|
139
|
+
</details>
|
|
140
|
+
|
|
141
|
+
<details>
|
|
142
|
+
<summary>Feishu (Lark) bridge configuration</summary>
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
feishu:
|
|
146
|
+
app_id: "YOUR_APP_ID"
|
|
147
|
+
app_secret: "YOUR_APP_SECRET"
|
|
148
|
+
allowed_users: ["open_id_1"] # Optional allowlist
|
|
149
|
+
```
|
|
150
|
+
</details>
|
|
151
|
+
|
|
152
|
+
### Run
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Launch with the new TUI (default — React + @openjaw/ink)
|
|
156
|
+
openjawagent.bat
|
|
157
|
+
node dist/main.js
|
|
158
|
+
|
|
159
|
+
# A/B test against the previous Ink UI (pre-rewrite)
|
|
160
|
+
node dist/main.js --legacy-ui
|
|
161
|
+
|
|
162
|
+
# Launch with messaging bridges
|
|
163
|
+
node dist/main.js --telegram # New TUI + Telegram
|
|
164
|
+
node dist/main.js --telegram --headless # Telegram only
|
|
165
|
+
node dist/main.js --teams # New TUI + Teams self-chat
|
|
166
|
+
node dist/main.js --feishu # New TUI + Feishu
|
|
167
|
+
node dist/main.js --wechat # New TUI + WeChat
|
|
168
|
+
|
|
169
|
+
# Launch with legacy readline REPL
|
|
170
|
+
node dist/main.js --legacy
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Usage
|
|
174
|
+
|
|
175
|
+
### Chat Naturally
|
|
176
|
+
|
|
177
|
+
Just type your request:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
❯ read my latest emails and summarize them
|
|
181
|
+
❯ send a teams message to PM Team Meeting saying "heading into meeting"
|
|
182
|
+
❯ what did Chenlu say in Teams this week?
|
|
183
|
+
❯ open the report in Excel and add a SUM formula in B10
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The agent reasons about your request, picks the right tools, executes them, and shows results with real-time feedback.
|
|
187
|
+
|
|
188
|
+
### Commands
|
|
189
|
+
|
|
190
|
+
| Command | Description |
|
|
191
|
+
|---------|-------------|
|
|
192
|
+
| `/help` | Show all commands |
|
|
193
|
+
| `/model` | Switch LLM provider/model (interactive picker) |
|
|
194
|
+
| `/connect` | Connect/disconnect/list LLM provider contexts |
|
|
195
|
+
| `/schedule "prompt" every 15m` | Schedule recurring tasks |
|
|
196
|
+
| `/schedule list` | Show active scheduled tasks |
|
|
197
|
+
| `/schedule stop <id>` | Cancel a scheduled task |
|
|
198
|
+
| `/tools` | List all available tools |
|
|
199
|
+
| `/mcp` | Manage MCP server connections |
|
|
200
|
+
| `/memory` | Search persistent memory |
|
|
201
|
+
| `/voice` | Toggle voice input/output |
|
|
202
|
+
| `/clear` | Clear conversation history (new session) |
|
|
203
|
+
| `/exit` | Quit the agent |
|
|
204
|
+
|
|
205
|
+
### Switch Models at Runtime
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
❯ /model
|
|
209
|
+
Current: anthropic/claude-sonnet-4-20250514
|
|
210
|
+
|
|
211
|
+
? Select model (↑↓ to navigate, Enter to select):
|
|
212
|
+
❯ anthropic/claude-opus-4.6
|
|
213
|
+
anthropic/claude-sonnet-4.6
|
|
214
|
+
anthropic/claude-sonnet-4-20250514
|
|
215
|
+
anthropic/claude-haiku-4.5
|
|
216
|
+
Maestro/gpt-5.4
|
|
217
|
+
Maestro/gpt-4.1
|
|
218
|
+
...
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
`/model` shows models from connected provider contexts only. If Maestro is connected, models are grouped under `Maestro` but still select the underlying `anthropic` or `openai` provider so the correct local proxy endpoint is used. Selection is saved to config and persists across restarts.
|
|
222
|
+
|
|
223
|
+
### Connect Providers
|
|
224
|
+
|
|
225
|
+
Use `/connect` after launch to pick the active provider context. Direct provider credentials are stored locally under `~/.openjaw-agent/auth.json`; secrets are not written to the repo config or shown in status output. Selecting a provider also applies its default model, and `/model` can change it afterward.
|
|
226
|
+
|
|
227
|
+
For direct Anthropic/OpenAI usage, run:
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
❯ /connect anthropic <api-key>
|
|
231
|
+
❯ /connect openai <api-key>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The command stores the API key locally and switches the active provider context. Local Maestro proxy mode does not require these keys:
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
❯ /connect maestro
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
OpenJaw Agent also supports GitHub Copilot as a first-class provider. The bundled Copilot client ID currently uses opencode's OAuth app because testing showed it exposes the full Copilot model list. You can override it with your organization's OAuth App client ID if needed.
|
|
241
|
+
|
|
242
|
+
```yaml
|
|
243
|
+
llm:
|
|
244
|
+
provider: github-copilot
|
|
245
|
+
model: gpt-5.4
|
|
246
|
+
api_key: proxy-token
|
|
247
|
+
copilot_oauth_client_id: Ov23li8tweQw6odWQebz
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
You can also override it with `GITHUB_COPILOT_CLIENT_ID` in the environment.
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
❯ /connect github-copilot
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
The command prints a GitHub device-login URL and one-time code, waits for authorization, then stores the credential. For GitHub Enterprise:
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
❯ /connect github-copilot enterprise company.ghe.com
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Then switch models:
|
|
263
|
+
|
|
264
|
+
```
|
|
265
|
+
❯ /model github-copilot gpt-5.4
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Useful credential commands:
|
|
269
|
+
|
|
270
|
+
| Command | Description |
|
|
271
|
+
|---------|-------------|
|
|
272
|
+
| `/connect` | Show connected provider contexts and switch options |
|
|
273
|
+
| `/connect maestro` | Use local Maestro proxy with no API key |
|
|
274
|
+
| `/connect anthropic <api-key>` | Store an Anthropic API key and select Anthropic |
|
|
275
|
+
| `/connect openai <api-key>` | Store an OpenAI API key and select OpenAI |
|
|
276
|
+
| `/connect list` | List connected contexts and stored credentials without showing secrets |
|
|
277
|
+
| `/connect status` | Show credential store path and provider status |
|
|
278
|
+
| `/connect disconnect` | Pick a connected provider, including Maestro, to disconnect |
|
|
279
|
+
|
|
280
|
+
Copilot model discovery uses GitHub Copilot's `/models` endpoint when connected and falls back to a static catalog when offline. GPT models use Copilot's OpenAI-compatible endpoints; Copilot Claude models exposed through `/v1/messages` use the Anthropic-compatible shim.
|
|
281
|
+
|
|
282
|
+
### Schedule Recurring Tasks
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
❯ /schedule "check my inbox for urgent emails" every 15m
|
|
286
|
+
✓ Scheduled task #1: runs every 15 minutes
|
|
287
|
+
|
|
288
|
+
❯ /schedule list
|
|
289
|
+
#1 every 15m runs: 3 last: 7:35 AM
|
|
290
|
+
"check my inbox for urgent emails"
|
|
291
|
+
|
|
292
|
+
❯ /schedule stop 1
|
|
293
|
+
✓ Task #1 stopped
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Sessions (Resume Conversations)
|
|
297
|
+
|
|
298
|
+
Sessions auto-save after each turn. Resume anytime:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
# List recent sessions
|
|
302
|
+
node dist/main.js --sessions
|
|
303
|
+
|
|
304
|
+
# Resume the most recent session
|
|
305
|
+
node dist/main.js --continue # or -c
|
|
306
|
+
|
|
307
|
+
# Resume a specific session
|
|
308
|
+
node dist/main.js --resume a1b2c3d4
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Skills
|
|
312
|
+
|
|
313
|
+
19 bundled skills provide multi-step workflows that the agent can invoke:
|
|
314
|
+
|
|
315
|
+
| Skill | Description |
|
|
316
|
+
|-------|-------------|
|
|
317
|
+
| `daily-briefing` | Morning briefing from emails, calendar, Teams |
|
|
318
|
+
| `deep-research` | Multi-source web research with synthesis |
|
|
319
|
+
| `email-drafting` | Compose polished emails |
|
|
320
|
+
| `email-with-attachment` | Send emails with file attachments |
|
|
321
|
+
| `meeting-summarizer` | Summarize meeting transcripts |
|
|
322
|
+
| `create-docx` | Create Word documents |
|
|
323
|
+
| `create-pptx` | Create PowerPoint presentations |
|
|
324
|
+
| `create-pdf-report` | Generate PDF reports |
|
|
325
|
+
| `data-analysis` | Analyze datasets and create charts |
|
|
326
|
+
| `web-research` | Quick web lookups |
|
|
327
|
+
| `translation` | Multi-language translation |
|
|
328
|
+
| `proofreading` | Grammar and style review |
|
|
329
|
+
| `summarization` | Summarize long documents |
|
|
330
|
+
| `desktop-cleanup` | Organize files and desktop |
|
|
331
|
+
| `doc-coauthoring` | Co-author documents with edit tracking |
|
|
332
|
+
| `internal-comms` | Draft internal communications |
|
|
333
|
+
| `competitive-battlecard` | Competitive analysis documents |
|
|
334
|
+
| `skill-creator` | Create new custom skills |
|
|
335
|
+
| `refresh-token` | Refresh auth tokens for bridges |
|
|
336
|
+
|
|
337
|
+
Custom skills can be added to `~/.openjaw-agent/skills/` as Markdown files. User skills override bundled skills of the same name.
|
|
338
|
+
|
|
339
|
+
## MCP Integration
|
|
340
|
+
|
|
341
|
+
OpenJaw Agent auto-discovers and connects to external MCP servers from 5 config sources (in priority order):
|
|
342
|
+
|
|
343
|
+
1. `~/.openjaw-agent/mcp.json` — Agent's own config (always trusted)
|
|
344
|
+
2. `.mcp.json` + parent directories — Claude Code project config
|
|
345
|
+
3. `~/.copilot/mcp-config.json` — GitHub Copilot CLI config
|
|
346
|
+
4. `~/.copilot/installed-plugins/` — Copilot marketplace plugins (WorkIQ, etc.)
|
|
347
|
+
5. `.vscode/mcp.json` — VS Code config (normalized to standard format)
|
|
348
|
+
|
|
349
|
+
Supports **stdio**, **SSE**, and **Streamable HTTP** transports. Tools from external servers appear as `mcp__<server>__<tool>` and can be used alongside built-in tools.
|
|
350
|
+
|
|
351
|
+
Use `/mcp` to interactively manage connections — toggle servers, view tools, reconnect.
|
|
352
|
+
|
|
353
|
+
## Architecture
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
openjaw-agent/
|
|
357
|
+
├── src/
|
|
358
|
+
│ ├── main.ts # CLI dispatch: new TUI default, --legacy-ui, --legacy
|
|
359
|
+
│ ├── entry.tsx # New TUI entry; renders React with @openjaw/ink
|
|
360
|
+
│ ├── bootstrap.ts # Initializes AgentLoop, tools, MCP, memory, voice, bridges
|
|
361
|
+
│ ├── agentBus.ts # In-process GatewayClient event/RPC bus
|
|
362
|
+
│ ├── agentEvents.ts # GatewayEvent type union for the ported UI
|
|
363
|
+
│ ├── eventBridge.ts # Converts AgentLoop chunks into GatewayEvents
|
|
364
|
+
│ ├── rpcHandlers.ts # Hermes-style RPC handlers for UI hooks
|
|
365
|
+
│ ├── app.tsx # New TUI root component
|
|
366
|
+
│ ├── app/ # Ported hermes hooks + nanostores UI state
|
|
367
|
+
│ │ ├── useMainApp.ts
|
|
368
|
+
│ │ ├── useSessionLifecycle.ts
|
|
369
|
+
│ │ ├── useSubmission.ts
|
|
370
|
+
│ │ └── uiStore.ts # Plus overlay/turn/delegation/input stores
|
|
371
|
+
│ ├── components/ # New TUI React components
|
|
372
|
+
│ │ ├── appChrome.tsx
|
|
373
|
+
│ │ ├── streamingAssistant.tsx
|
|
374
|
+
│ │ ├── sessionPicker.tsx
|
|
375
|
+
│ │ ├── modelPicker.tsx
|
|
376
|
+
│ │ └── todoPanel.tsx
|
|
377
|
+
│ ├── legacy-ink-ui.tsx # Previous Ink UI (--legacy-ui)
|
|
378
|
+
│ ├── agent-loop.ts # ReAct orchestrator (parallel tools, usage tracking)
|
|
379
|
+
│ ├── mcp-client.ts # MCP client — auto-discovers external servers
|
|
380
|
+
│ ├── bridges/
|
|
381
|
+
│ │ ├── telegram.ts # Telegram bot bridge (long-polling)
|
|
382
|
+
│ │ ├── teams.ts # Teams self-chat bridge (Graph API)
|
|
383
|
+
│ │ ├── feishu.ts # Feishu/Lark bridge (WebSocket)
|
|
384
|
+
│ │ ├── wechat.ts # WeChat iLink bridge (HTTP polling)
|
|
385
|
+
│ │ └── format.ts # Platform-specific message formatting
|
|
386
|
+
│ ├── voice/
|
|
387
|
+
│ │ ├── index.ts # Voice manager (enable/disable, settings)
|
|
388
|
+
│ │ ├── tts.ts # Text-to-speech (edge-tts)
|
|
389
|
+
│ │ └── stt.ts # Speech-to-text (Windows Speech Recognition)
|
|
390
|
+
│ ├── prompts/
|
|
391
|
+
│ │ ├── index.ts # Structured prompt assembly (static/dynamic boundary)
|
|
392
|
+
│ │ ├── sections.ts # Memoization framework + SYSTEM_PROMPT_DYNAMIC_BOUNDARY
|
|
393
|
+
│ │ ├── identity.ts # Static: agent persona
|
|
394
|
+
│ │ ├── reasoning.ts # Static: ReAct rules
|
|
395
|
+
│ │ ├── safety.ts # Static: safety guardrails
|
|
396
|
+
│ │ ├── computerUse.ts # Static: computer use guidelines
|
|
397
|
+
│ │ ├── user.ts # Dynamic: user preferences
|
|
398
|
+
│ │ ├── memory.ts # Dynamic: persistent memory
|
|
399
|
+
│ │ └── context.ts # Dynamic: runtime context
|
|
400
|
+
│ ├── providers/
|
|
401
|
+
│ │ ├── types.ts # LLMProvider + streaming + usage types
|
|
402
|
+
│ │ ├── anthropic.ts # Anthropic (cache_control, streaming, usage)
|
|
403
|
+
│ │ ├── openai.ts # OpenAI (Responses + Completions API, usage)
|
|
404
|
+
│ │ ├── cache-control.ts # System prompt → cache-scoped blocks
|
|
405
|
+
│ │ └── index.ts # Provider factory
|
|
406
|
+
│ ├── skills/
|
|
407
|
+
│ │ └── registry.ts # Skill discovery (bundled + user overrides)
|
|
408
|
+
│ ├── tools/
|
|
409
|
+
│ │ └── skill-tool.ts # LLM-callable skill invocation tool
|
|
410
|
+
│ ├── utils/
|
|
411
|
+
│ │ └── frontmatter.ts # Markdown frontmatter parser for skills
|
|
412
|
+
│ ├── cost-tracker.ts # Per-model pricing + session cost tracking
|
|
413
|
+
│ ├── context-manager.ts # Token estimation + context window warnings
|
|
414
|
+
│ ├── cache-monitor.ts # Prompt cache break detection between turns
|
|
415
|
+
│ ├── telemetry.ts # JSONL event logging (~/.openjaw-agent/telemetry/)
|
|
416
|
+
│ ├── config.ts # Config loader (~/.openjaw-agent/config.yaml)
|
|
417
|
+
│ ├── session.ts # Session persistence + resume
|
|
418
|
+
│ ├── scheduler.ts # Recurring task scheduler
|
|
419
|
+
│ ├── fork.ts # Background sub-agent spawning
|
|
420
|
+
│ ├── pet.ts # Pet companion system (Chinese mythical creatures)
|
|
421
|
+
│ ├── computer-use.ts # Anthropic computer use executor
|
|
422
|
+
│ ├── clipboard-image.ts # Windows clipboard image reader
|
|
423
|
+
│ ├── image-resize.ts # Image processing for vision APIs
|
|
424
|
+
│ └── repl.ts # Legacy readline REPL (--legacy mode)
|
|
425
|
+
├── prompts/ # Markdown prompt files
|
|
426
|
+
│ ├── IDENTITY.md
|
|
427
|
+
│ ├── REASONING.md
|
|
428
|
+
│ ├── SAFETY.md
|
|
429
|
+
│ ├── COMPUTER_USE.md
|
|
430
|
+
│ └── USER.md
|
|
431
|
+
├── skills/ # Bundled skill definitions (19 skills)
|
|
432
|
+
├── docs/
|
|
433
|
+
│ └── TUI.md # Concise TUI rewrite overview
|
|
434
|
+
├── packages/
|
|
435
|
+
│ └── openjaw-ink/ # Vendored @openjaw/ink renderer forked from @hermes/ink
|
|
436
|
+
├── config.yaml # Bundled default config
|
|
437
|
+
├── install.bat # One-click Windows installer
|
|
438
|
+
├── openjawagent.bat # Launch script
|
|
439
|
+
├── package.json
|
|
440
|
+
└── tsconfig.json
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Key Design Decisions
|
|
444
|
+
|
|
445
|
+
**TUI Rewrite** — The default UI is an in-process React TUI rendered by `@openjaw/ink`. `GatewayEvent` streaming and RPC handlers isolate AgentLoop/service logic from ported hermes hooks, while nanostores keep UI state small and composable. Use `--legacy-ui` for the previous Ink UI when comparing behavior.
|
|
446
|
+
|
|
447
|
+
**ReAct Loop** — The agent loop implements a Reasoning + Acting pattern: the LLM reasons about the request, selects tools, the loop executes them in parallel, feeds results back, and repeats until done.
|
|
448
|
+
|
|
449
|
+
**Prompt Caching** — The system prompt is split into **static** and **dynamic** sections separated by a boundary marker. Static sections (identity, reasoning, safety, computer use) get Anthropic's `cache_control: { type: 'ephemeral' }` for prompt caching. Dynamic sections (user profile, memory, context) are memoized per session. Cache breaks are tracked by `CacheMonitor` to surface cost spikes.
|
|
450
|
+
|
|
451
|
+
**Tool Permission Model** — Sensitive tools (shell commands, file deletion, file writes) trigger an interactive permission dialog. Users can approve once or allow-all for the session.
|
|
452
|
+
|
|
453
|
+
**Fork System** — The agent can spawn background sub-agents for parallel work. Forks share the parent's system prompt and tools but run with their own conversation history.
|
|
454
|
+
|
|
455
|
+
**Telemetry** — Every agent turn is logged as structured JSONL to `~/.openjaw-agent/telemetry/` with token counts, cost, duration, and cache metrics. Files rotate daily.
|
|
456
|
+
|
|
457
|
+
### Provider Plugin Architecture
|
|
458
|
+
|
|
459
|
+
Adding a new LLM provider:
|
|
460
|
+
|
|
461
|
+
1. Create `src/providers/yourprovider.ts` implementing `LLMProvider`
|
|
462
|
+
2. Add `case 'yourprovider':` to `src/providers/index.ts`
|
|
463
|
+
3. That's it — config-driven, no other changes needed
|
|
464
|
+
|
|
465
|
+
### Shared Memory
|
|
466
|
+
|
|
467
|
+
Both OpenJaw Agent and OpenJaw MCP server share the same SQLite database at `~/.openjaw/memory.db`:
|
|
468
|
+
|
|
469
|
+
- Hybrid search: FTS5 keyword + Jaccard + HRR semantic similarity
|
|
470
|
+
- Searchable via `/memory` command or `memory_search` tool
|
|
471
|
+
|
|
472
|
+
No duplication — write from either mode, search from either mode.
|
|
473
|
+
|
|
474
|
+
### No Conflicts with MCP Server
|
|
475
|
+
|
|
476
|
+
Both can run simultaneously:
|
|
477
|
+
|
|
478
|
+
| | MCP Server | Agent |
|
|
479
|
+
|-|-----------|-------|
|
|
480
|
+
| **Transport** | stdio (pipe) | terminal (readline/Ink) |
|
|
481
|
+
| **Ports** | none | none |
|
|
482
|
+
| **Config** | `~/.openjaw/config.yaml` | `~/.openjaw-agent/config.yaml` |
|
|
483
|
+
| **Memory** | `~/.openjaw/memory/` (shared) | `~/.openjaw/memory/` (shared) |
|
|
484
|
+
| **Sessions** | managed by host | `~/.openjaw-agent/sessions/` |
|
|
485
|
+
| **Telemetry** | — | `~/.openjaw-agent/telemetry/` |
|
|
486
|
+
|
|
487
|
+
## Build from Source
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
cd projects/openjaw-agent
|
|
491
|
+
|
|
492
|
+
# Install dependencies (includes openjaw core as local dependency)
|
|
493
|
+
npm install
|
|
494
|
+
|
|
495
|
+
# Build TypeScript
|
|
496
|
+
npm run build
|
|
497
|
+
|
|
498
|
+
# Run
|
|
499
|
+
node dist/main.js
|
|
500
|
+
|
|
501
|
+
# Or use the batch file
|
|
502
|
+
openjawagent.bat
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Development
|
|
506
|
+
|
|
507
|
+
```bash
|
|
508
|
+
# Run in dev mode (tsx, no build needed)
|
|
509
|
+
npm run dev
|
|
510
|
+
|
|
511
|
+
# Rebuild after changes
|
|
512
|
+
npm run build
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
## CLI Reference
|
|
516
|
+
|
|
517
|
+
```
|
|
518
|
+
openjaw-agent Start new session (new TUI)
|
|
519
|
+
openjaw-agent --legacy-ui Start previous Ink UI (pre-rewrite) for A/B comparison
|
|
520
|
+
openjaw-agent --legacy Start legacy readline REPL
|
|
521
|
+
openjaw-agent --resume <session-id> Resume a specific session
|
|
522
|
+
openjaw-agent --continue (-c) Resume the most recent session
|
|
523
|
+
openjaw-agent --sessions List recent sessions
|
|
524
|
+
openjaw-agent --telegram New TUI + Telegram bridge (hybrid)
|
|
525
|
+
openjaw-agent --telegram --headless Telegram only (no terminal UI)
|
|
526
|
+
openjaw-agent --teams New TUI + Teams self-chat bridge
|
|
527
|
+
openjaw-agent --feishu New TUI + Feishu bot bridge
|
|
528
|
+
openjaw-agent --wechat New TUI + WeChat iLink bridge
|
|
529
|
+
openjaw-agent --help Show help
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
## Environment Variables (Optional Overrides)
|
|
533
|
+
|
|
534
|
+
| Variable | Description |
|
|
535
|
+
|----------|-------------|
|
|
536
|
+
| `ANTHROPIC_API_KEY` | Anthropic API key (overrides config) |
|
|
537
|
+
| `ANTHROPIC_AUTH_TOKEN` | Anthropic auth token (for proxy) |
|
|
538
|
+
| `ANTHROPIC_BASE_URL` | Anthropic proxy URL |
|
|
539
|
+
| `OPENAI_API_KEY` | OpenAI API key (overrides config) |
|
|
540
|
+
| `OPENAI_BASE_URL` | OpenAI proxy URL |
|
|
541
|
+
|
|
542
|
+
Config file values are the default. Environment variables override when set.
|
|
543
|
+
|
|
544
|
+
## License
|
|
545
|
+
|
|
546
|
+
Internal use only. Part of the [BravoPM](https://github.com/m365-core/bravopm) monorepo.
|
package/config.yaml
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# OpenJaw Agent Configuration
|
|
2
|
+
# Recommended first-run flow:
|
|
3
|
+
# 1. Launch OpenJaw Agent.
|
|
4
|
+
# 2. Run /connect to pick Maestro, Anthropic, OpenAI, or GitHub Copilot.
|
|
5
|
+
# 3. Run /model to choose a model from connected providers.
|
|
6
|
+
#
|
|
7
|
+
# Edit this file only for advanced defaults or non-interactive deployments.
|
|
8
|
+
# After editing, restart the agent for changes to take effect.
|
|
9
|
+
|
|
10
|
+
llm:
|
|
11
|
+
# Provider: anthropic | openai | github-copilot
|
|
12
|
+
# /connect updates this automatically when you switch provider contexts.
|
|
13
|
+
provider: anthropic
|
|
14
|
+
|
|
15
|
+
# Model name (must match the provider's supported models).
|
|
16
|
+
# /connect picks a provider default; /model updates this interactively.
|
|
17
|
+
model: claude-sonnet-4-20250514
|
|
18
|
+
|
|
19
|
+
# API key placeholder.
|
|
20
|
+
# Direct Anthropic/OpenAI keys and Copilot OAuth tokens are stored by /connect
|
|
21
|
+
# in ~/.openjaw-agent/auth.json, not in this file.
|
|
22
|
+
api_key: proxy-token
|
|
23
|
+
|
|
24
|
+
# Default local Maestro Anthropic proxy endpoint.
|
|
25
|
+
# /connect maestro selects Maestro; /model chooses the exact Maestro model.
|
|
26
|
+
# Direct provider connections leave base_url empty.
|
|
27
|
+
base_url: http://localhost:23333/api/anthropic
|
|
28
|
+
|
|
29
|
+
# Max output tokens per response (16384 matches Claude Code default)
|
|
30
|
+
max_tokens: 16384
|
|
31
|
+
|
|
32
|
+
# Temperature (0.0 = deterministic, 1.0 = creative)
|
|
33
|
+
temperature: 0.7
|
|
34
|
+
|
|
35
|
+
# Optional advanced OpenAI proxy tool exposure:
|
|
36
|
+
# openai_tool_mode: auto # auto | compact | full
|
|
37
|
+
# openai_max_tools: 32
|
|
38
|
+
|
|
39
|
+
# Optional for provider: github-copilot with GitHub Enterprise.
|
|
40
|
+
# Usually set by /connect github-copilot enterprise <domain>.
|
|
41
|
+
# copilot_enterprise_url: company.ghe.com
|
|
42
|
+
#
|
|
43
|
+
# GitHub OAuth App client ID used by /connect github-copilot.
|
|
44
|
+
# Currently defaults to opencode's client ID because it exposes the full Copilot model list.
|
|
45
|
+
copilot_oauth_client_id: Ov23li8tweQw6odWQebz
|
|
46
|
+
|
|
47
|
+
# ─── Example: OpenAI direct (normally use: /connect openai <api-key>) ───
|
|
48
|
+
# llm:
|
|
49
|
+
# provider: openai
|
|
50
|
+
# model: gpt-5.4
|
|
51
|
+
# api_key: proxy-token # actual key is read from ~/.openjaw-agent/auth.json
|
|
52
|
+
# max_tokens: 4096
|
|
53
|
+
# temperature: 0.7
|
|
54
|
+
|
|
55
|
+
# ─── Example: GitHub Copilot ───
|
|
56
|
+
# First run: /connect github-copilot
|
|
57
|
+
# Enterprise: /connect github-copilot enterprise company.ghe.com
|
|
58
|
+
# llm:
|
|
59
|
+
# provider: github-copilot
|
|
60
|
+
# model: gpt-5.4
|
|
61
|
+
# api_key: proxy-token # token is read from ~/.openjaw-agent/auth.json
|
|
62
|
+
# copilot_oauth_client_id: Ov23li8tweQw6odWQebz
|
|
63
|
+
# max_tokens: 16384
|
|
64
|
+
# temperature: 0.7
|
|
65
|
+
|
|
66
|
+
# ─── Example: Anthropic direct (normally use: /connect anthropic <api-key>) ───
|
|
67
|
+
# llm:
|
|
68
|
+
# provider: anthropic
|
|
69
|
+
# model: claude-sonnet-4-20250514
|
|
70
|
+
# api_key: proxy-token # actual key is read from ~/.openjaw-agent/auth.json
|
|
71
|
+
# max_tokens: 4096
|
|
72
|
+
# temperature: 0.7
|