localant 1.0.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 +290 -0
- package/SECURITY.md +87 -0
- package/examples/skills/hello-world/CHANGELOG.md +4 -0
- package/examples/skills/hello-world/LICENSE +1 -0
- package/examples/skills/hello-world/README.md +20 -0
- package/examples/skills/hello-world/examples/example.json +1 -0
- package/examples/skills/hello-world/package.json +9 -0
- package/examples/skills/hello-world/skill.json +32 -0
- package/examples/skills/hello-world/src/index.ts +19 -0
- package/examples/skills/hello-world/tests/index.test.ts +19 -0
- package/package.json +63 -0
- package/packages/cli/dist/bin.d.ts +3 -0
- package/packages/cli/dist/bin.d.ts.map +1 -0
- package/packages/cli/dist/bin.js +261 -0
- package/packages/cli/dist/bin.js.map +1 -0
- package/packages/cli/dist/doctor.d.ts +3 -0
- package/packages/cli/dist/doctor.d.ts.map +1 -0
- package/packages/cli/dist/doctor.js +35 -0
- package/packages/cli/dist/doctor.js.map +1 -0
- package/packages/cli/dist/index.d.ts +3 -0
- package/packages/cli/dist/index.d.ts.map +1 -0
- package/packages/cli/dist/index.js +3 -0
- package/packages/cli/dist/index.js.map +1 -0
- package/packages/cli/dist/runtime.d.ts +11 -0
- package/packages/cli/dist/runtime.d.ts.map +1 -0
- package/packages/cli/dist/runtime.js +82 -0
- package/packages/cli/dist/runtime.js.map +1 -0
- package/packages/cli/dist/util.d.ts +18 -0
- package/packages/cli/dist/util.d.ts.map +1 -0
- package/packages/cli/dist/util.js +47 -0
- package/packages/cli/dist/util.js.map +1 -0
- package/packages/cli/package.json +19 -0
- package/packages/dashboard/dist/index.d.ts +10 -0
- package/packages/dashboard/dist/index.d.ts.map +1 -0
- package/packages/dashboard/dist/index.js +178 -0
- package/packages/dashboard/dist/index.js.map +1 -0
- package/packages/dashboard/package.json +10 -0
- package/packages/gateway/dist/gateway.d.ts +85 -0
- package/packages/gateway/dist/gateway.d.ts.map +1 -0
- package/packages/gateway/dist/gateway.js +234 -0
- package/packages/gateway/dist/gateway.js.map +1 -0
- package/packages/gateway/dist/index.d.ts +13 -0
- package/packages/gateway/dist/index.d.ts.map +1 -0
- package/packages/gateway/dist/index.js +16 -0
- package/packages/gateway/dist/index.js.map +1 -0
- package/packages/gateway/dist/managers/coding-agent-manager.d.ts +71 -0
- package/packages/gateway/dist/managers/coding-agent-manager.d.ts.map +1 -0
- package/packages/gateway/dist/managers/coding-agent-manager.js +179 -0
- package/packages/gateway/dist/managers/coding-agent-manager.js.map +1 -0
- package/packages/gateway/dist/managers/fs-manager.d.ts +63 -0
- package/packages/gateway/dist/managers/fs-manager.d.ts.map +1 -0
- package/packages/gateway/dist/managers/fs-manager.js +229 -0
- package/packages/gateway/dist/managers/fs-manager.js.map +1 -0
- package/packages/gateway/dist/managers/git-manager.d.ts +21 -0
- package/packages/gateway/dist/managers/git-manager.d.ts.map +1 -0
- package/packages/gateway/dist/managers/git-manager.js +67 -0
- package/packages/gateway/dist/managers/git-manager.js.map +1 -0
- package/packages/gateway/dist/managers/mcp-bridge.d.ts +26 -0
- package/packages/gateway/dist/managers/mcp-bridge.d.ts.map +1 -0
- package/packages/gateway/dist/managers/mcp-bridge.js +92 -0
- package/packages/gateway/dist/managers/mcp-bridge.js.map +1 -0
- package/packages/gateway/dist/managers/project-registry.d.ts +17 -0
- package/packages/gateway/dist/managers/project-registry.d.ts.map +1 -0
- package/packages/gateway/dist/managers/project-registry.js +90 -0
- package/packages/gateway/dist/managers/project-registry.js.map +1 -0
- package/packages/gateway/dist/managers/shell-manager.d.ts +48 -0
- package/packages/gateway/dist/managers/shell-manager.d.ts.map +1 -0
- package/packages/gateway/dist/managers/shell-manager.js +132 -0
- package/packages/gateway/dist/managers/shell-manager.js.map +1 -0
- package/packages/gateway/dist/managers/skill-runtime.d.ts +37 -0
- package/packages/gateway/dist/managers/skill-runtime.d.ts.map +1 -0
- package/packages/gateway/dist/managers/skill-runtime.js +310 -0
- package/packages/gateway/dist/managers/skill-runtime.js.map +1 -0
- package/packages/gateway/dist/managers/tunnel-manager.d.ts +23 -0
- package/packages/gateway/dist/managers/tunnel-manager.d.ts.map +1 -0
- package/packages/gateway/dist/managers/tunnel-manager.js +106 -0
- package/packages/gateway/dist/managers/tunnel-manager.js.map +1 -0
- package/packages/gateway/dist/registry.d.ts +28 -0
- package/packages/gateway/dist/registry.d.ts.map +1 -0
- package/packages/gateway/dist/registry.js +20 -0
- package/packages/gateway/dist/registry.js.map +1 -0
- package/packages/gateway/dist/security/command-guard.d.ts +35 -0
- package/packages/gateway/dist/security/command-guard.d.ts.map +1 -0
- package/packages/gateway/dist/security/command-guard.js +105 -0
- package/packages/gateway/dist/security/command-guard.js.map +1 -0
- package/packages/gateway/dist/security/path-guard.d.ts +31 -0
- package/packages/gateway/dist/security/path-guard.d.ts.map +1 -0
- package/packages/gateway/dist/security/path-guard.js +101 -0
- package/packages/gateway/dist/security/path-guard.js.map +1 -0
- package/packages/gateway/dist/skill-runner.d.ts +2 -0
- package/packages/gateway/dist/skill-runner.d.ts.map +1 -0
- package/packages/gateway/dist/skill-runner.js +38 -0
- package/packages/gateway/dist/skill-runner.js.map +1 -0
- package/packages/gateway/dist/stores/approval-store.d.ts +34 -0
- package/packages/gateway/dist/stores/approval-store.d.ts.map +1 -0
- package/packages/gateway/dist/stores/approval-store.js +108 -0
- package/packages/gateway/dist/stores/approval-store.js.map +1 -0
- package/packages/gateway/dist/stores/audit-log.d.ts +23 -0
- package/packages/gateway/dist/stores/audit-log.d.ts.map +1 -0
- package/packages/gateway/dist/stores/audit-log.js +70 -0
- package/packages/gateway/dist/stores/audit-log.js.map +1 -0
- package/packages/gateway/dist/stores/config-store.d.ts +14 -0
- package/packages/gateway/dist/stores/config-store.d.ts.map +1 -0
- package/packages/gateway/dist/stores/config-store.js +57 -0
- package/packages/gateway/dist/stores/config-store.js.map +1 -0
- package/packages/gateway/dist/stores/secret-vault.d.ts +23 -0
- package/packages/gateway/dist/stores/secret-vault.d.ts.map +1 -0
- package/packages/gateway/dist/stores/secret-vault.js +74 -0
- package/packages/gateway/dist/stores/secret-vault.js.map +1 -0
- package/packages/gateway/dist/tools/adapters.d.ts +8 -0
- package/packages/gateway/dist/tools/adapters.d.ts.map +1 -0
- package/packages/gateway/dist/tools/adapters.js +178 -0
- package/packages/gateway/dist/tools/adapters.js.map +1 -0
- package/packages/gateway/dist/tools/adb.d.ts +3 -0
- package/packages/gateway/dist/tools/adb.d.ts.map +1 -0
- package/packages/gateway/dist/tools/adb.js +60 -0
- package/packages/gateway/dist/tools/adb.js.map +1 -0
- package/packages/gateway/dist/tools/article.d.ts +3 -0
- package/packages/gateway/dist/tools/article.d.ts.map +1 -0
- package/packages/gateway/dist/tools/article.js +230 -0
- package/packages/gateway/dist/tools/article.js.map +1 -0
- package/packages/gateway/dist/tools/audit-approval.d.ts +4 -0
- package/packages/gateway/dist/tools/audit-approval.d.ts.map +1 -0
- package/packages/gateway/dist/tools/audit-approval.js +64 -0
- package/packages/gateway/dist/tools/audit-approval.js.map +1 -0
- package/packages/gateway/dist/tools/browser.d.ts +3 -0
- package/packages/gateway/dist/tools/browser.d.ts.map +1 -0
- package/packages/gateway/dist/tools/browser.js +55 -0
- package/packages/gateway/dist/tools/browser.js.map +1 -0
- package/packages/gateway/dist/tools/coding-agent.d.ts +3 -0
- package/packages/gateway/dist/tools/coding-agent.d.ts.map +1 -0
- package/packages/gateway/dist/tools/coding-agent.js +103 -0
- package/packages/gateway/dist/tools/coding-agent.js.map +1 -0
- package/packages/gateway/dist/tools/filesystem.d.ts +3 -0
- package/packages/gateway/dist/tools/filesystem.d.ts.map +1 -0
- package/packages/gateway/dist/tools/filesystem.js +141 -0
- package/packages/gateway/dist/tools/filesystem.js.map +1 -0
- package/packages/gateway/dist/tools/git.d.ts +3 -0
- package/packages/gateway/dist/tools/git.d.ts.map +1 -0
- package/packages/gateway/dist/tools/git.js +92 -0
- package/packages/gateway/dist/tools/git.js.map +1 -0
- package/packages/gateway/dist/tools/index.d.ts +4 -0
- package/packages/gateway/dist/tools/index.d.ts.map +1 -0
- package/packages/gateway/dist/tools/index.js +29 -0
- package/packages/gateway/dist/tools/index.js.map +1 -0
- package/packages/gateway/dist/tools/project.d.ts +3 -0
- package/packages/gateway/dist/tools/project.d.ts.map +1 -0
- package/packages/gateway/dist/tools/project.js +86 -0
- package/packages/gateway/dist/tools/project.js.map +1 -0
- package/packages/gateway/dist/tools/shell.d.ts +3 -0
- package/packages/gateway/dist/tools/shell.d.ts.map +1 -0
- package/packages/gateway/dist/tools/shell.js +98 -0
- package/packages/gateway/dist/tools/shell.js.map +1 -0
- package/packages/gateway/dist/tools/skill.d.ts +3 -0
- package/packages/gateway/dist/tools/skill.d.ts.map +1 -0
- package/packages/gateway/dist/tools/skill.js +231 -0
- package/packages/gateway/dist/tools/skill.js.map +1 -0
- package/packages/gateway/dist/tools/system.d.ts +3 -0
- package/packages/gateway/dist/tools/system.d.ts.map +1 -0
- package/packages/gateway/dist/tools/system.js +78 -0
- package/packages/gateway/dist/tools/system.js.map +1 -0
- package/packages/gateway/dist/util/exec.d.ts +21 -0
- package/packages/gateway/dist/util/exec.d.ts.map +1 -0
- package/packages/gateway/dist/util/exec.js +50 -0
- package/packages/gateway/dist/util/exec.js.map +1 -0
- package/packages/gateway/package.json +18 -0
- package/packages/mcp/dist/http-server.d.ts +16 -0
- package/packages/mcp/dist/http-server.d.ts.map +1 -0
- package/packages/mcp/dist/http-server.js +138 -0
- package/packages/mcp/dist/http-server.js.map +1 -0
- package/packages/mcp/dist/index.d.ts +4 -0
- package/packages/mcp/dist/index.d.ts.map +1 -0
- package/packages/mcp/dist/index.js +3 -0
- package/packages/mcp/dist/index.js.map +1 -0
- package/packages/mcp/dist/mcp-server.d.ts +9 -0
- package/packages/mcp/dist/mcp-server.d.ts.map +1 -0
- package/packages/mcp/dist/mcp-server.js +26 -0
- package/packages/mcp/dist/mcp-server.js.map +1 -0
- package/packages/mcp/package.json +18 -0
- package/packages/shared/dist/config.d.ts +314 -0
- package/packages/shared/dist/config.d.ts.map +1 -0
- package/packages/shared/dist/config.js +146 -0
- package/packages/shared/dist/config.js.map +1 -0
- package/packages/shared/dist/index.d.ts +8 -0
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +8 -0
- package/packages/shared/dist/index.js.map +1 -0
- package/packages/shared/dist/logger.d.ts +8 -0
- package/packages/shared/dist/logger.d.ts.map +1 -0
- package/packages/shared/dist/logger.js +26 -0
- package/packages/shared/dist/logger.js.map +1 -0
- package/packages/shared/dist/net.d.ts +10 -0
- package/packages/shared/dist/net.d.ts.map +1 -0
- package/packages/shared/dist/net.js +35 -0
- package/packages/shared/dist/net.js.map +1 -0
- package/packages/shared/dist/paths.d.ts +30 -0
- package/packages/shared/dist/paths.d.ts.map +1 -0
- package/packages/shared/dist/paths.js +70 -0
- package/packages/shared/dist/paths.js.map +1 -0
- package/packages/shared/dist/redaction.d.ts +15 -0
- package/packages/shared/dist/redaction.d.ts.map +1 -0
- package/packages/shared/dist/redaction.js +58 -0
- package/packages/shared/dist/redaction.js.map +1 -0
- package/packages/shared/dist/risk.d.ts +23 -0
- package/packages/shared/dist/risk.d.ts.map +1 -0
- package/packages/shared/dist/risk.js +28 -0
- package/packages/shared/dist/risk.js.map +1 -0
- package/packages/shared/dist/types.d.ts +94 -0
- package/packages/shared/dist/types.d.ts.map +1 -0
- package/packages/shared/dist/types.js +2 -0
- package/packages/shared/dist/types.js.map +1 -0
- package/packages/shared/package.json +13 -0
- package/packages/skill-sdk/dist/index.d.ts +36 -0
- package/packages/skill-sdk/dist/index.d.ts.map +1 -0
- package/packages/skill-sdk/dist/index.js +20 -0
- package/packages/skill-sdk/dist/index.js.map +1 -0
- package/packages/skill-sdk/package.json +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 chatgpt-local-app contributors
|
|
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,290 @@
|
|
|
1
|
+
# LocalAnt
|
|
2
|
+
|
|
3
|
+
> **Use ChatGPT as the brain. Use your local computer as the hands.**
|
|
4
|
+
|
|
5
|
+
`LocalAnt` lets you use ChatGPT as the brain and your local computer as the hands.
|
|
6
|
+
|
|
7
|
+
It exposes safe, permissioned local skills to ChatGPT through MCP:
|
|
8
|
+
run approved commands, inspect projects, manage files, call coding agents like
|
|
9
|
+
Claude Code or Codex, control browser/ADB, publish articles, and create your own
|
|
10
|
+
local skills — all behind a default-deny security model with local approval and
|
|
11
|
+
full audit logging.
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
ChatGPT
|
|
15
|
+
↓ Apps SDK / MCP Connector (Streamable HTTP /mcp)
|
|
16
|
+
LocalAnt ── Gateway · Risk engine · Approval queue · Audit log · Dashboard
|
|
17
|
+
↓ Local PC
|
|
18
|
+
├─ Shell (allowlisted) · Filesystem (allowlisted) · Git
|
|
19
|
+
├─ Claude Code / Codex (plan → approve → execute → validate → diff)
|
|
20
|
+
├─ Browser (Playwright, isolated profile) · Android (ADB)
|
|
21
|
+
├─ Articles (Zenn / Qiita / note) · Custom Skills
|
|
22
|
+
└─ Adapters: OpenClaw · Desktop Commander · any MCP server
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## What is LocalAnt?
|
|
28
|
+
|
|
29
|
+
A **local-first MCP Gateway** for ChatGPT. ChatGPT is the conversational UI and
|
|
30
|
+
decision-maker; your PC is the execution environment. The gateway publishes a
|
|
31
|
+
catalog of **140+ permissioned tools** over the Model Context Protocol, which
|
|
32
|
+
ChatGPT's Developer-Mode connectors can call.
|
|
33
|
+
|
|
34
|
+
The design is inspired by OpenClaw (local gateway + skills + registry),
|
|
35
|
+
Desktop Commander (local PC control + audit + hardening), supergateway
|
|
36
|
+
(stdio→Streamable-HTTP `/mcp`), and mcp-proxy (bundling MCP servers) — but the
|
|
37
|
+
brain is **ChatGPT**, and every capability is wrapped in permissions, approval,
|
|
38
|
+
and audit.
|
|
39
|
+
|
|
40
|
+
## Why ChatGPT as brain, local PC as hands?
|
|
41
|
+
|
|
42
|
+
- ChatGPT is great at reasoning, planning, and conversation.
|
|
43
|
+
- Your PC is where your code, files, devices, and tools actually live.
|
|
44
|
+
- Handing ChatGPT a raw shell is dangerous. Instead, this gateway gives it a
|
|
45
|
+
**curated, permissioned surface** with local approval for anything risky.
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- 🔒 **Default-deny security**: allowlisted dirs/commands, blocklist, path &
|
|
50
|
+
symlink traversal prevention, secret vault + redaction.
|
|
51
|
+
- ✅ **Local approval queue**: risk-2+ tools require explicit approval in the
|
|
52
|
+
dashboard or CLI — ChatGPT's confirmation is never trusted alone.
|
|
53
|
+
- 🧾 **Full audit log**: every tool call recorded (with secrets redacted).
|
|
54
|
+
- 🧩 **Skill system**: create, validate, enable, run, install-from-git,
|
|
55
|
+
publish, and **generate skills from ChatGPT** (always saved disabled).
|
|
56
|
+
- 🤖 **Coding agents**: drive Claude Code / Codex (plan → approve → execute →
|
|
57
|
+
validate → diff) on registered projects.
|
|
58
|
+
- 🖥️ **Local dashboard**: status, approvals, audit, skills, projects, secrets, agents.
|
|
59
|
+
- 🌐 **3-minute setup** with Cloudflare Tunnel / ngrok and clipboard copy.
|
|
60
|
+
- 🔌 **Adapters** for OpenClaw, Desktop Commander, and arbitrary MCP servers.
|
|
61
|
+
|
|
62
|
+
## 3-minute setup
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx -y localant setup
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
or:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm install -g localant
|
|
72
|
+
localant setup
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`setup` checks your environment, initializes config, generates an auth token,
|
|
76
|
+
enables built-in skills, starts the gateway + dashboard, opens a public tunnel,
|
|
77
|
+
copies the MCP URL to your clipboard, and prints the ChatGPT connection steps.
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
✅ LocalAnt is running
|
|
81
|
+
|
|
82
|
+
Local Gateway: http://127.0.0.1:8787
|
|
83
|
+
Dashboard: http://127.0.0.1:8788
|
|
84
|
+
MCP Endpoint: https://xxxxx.trycloudflare.com/mcp?key=********
|
|
85
|
+
|
|
86
|
+
Connect ChatGPT:
|
|
87
|
+
1. Open ChatGPT → Settings → Apps & Connectors
|
|
88
|
+
2. Advanced settings → Developer Mode ON
|
|
89
|
+
3. Connectors → Create
|
|
90
|
+
4. Paste the MCP URL above
|
|
91
|
+
5. Name it: LocalAnt
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
> **From source** (this repo): `pnpm install && pnpm build && node packages/cli/dist/bin.js setup`
|
|
95
|
+
|
|
96
|
+
## ChatGPT setup
|
|
97
|
+
|
|
98
|
+
1. ChatGPT → **Settings → Apps & Connectors**
|
|
99
|
+
2. **Advanced settings → Developer Mode ON**
|
|
100
|
+
3. **Connectors → Create**
|
|
101
|
+
4. Paste the **MCP URL** (`https://…/mcp?key=<token>`)
|
|
102
|
+
5. Name it **LocalAnt**
|
|
103
|
+
6. Ask ChatGPT: *"Run health check on my local app"*
|
|
104
|
+
|
|
105
|
+
The token is embedded in the URL so the connector authenticates even where
|
|
106
|
+
custom headers aren't available. You can also send `Authorization: Bearer <token>`.
|
|
107
|
+
See [docs/chatgpt-setup.md](docs/chatgpt-setup.md).
|
|
108
|
+
|
|
109
|
+
## Security model
|
|
110
|
+
|
|
111
|
+
| Risk | Meaning | Approval |
|
|
112
|
+
|------|---------|----------|
|
|
113
|
+
| 0 | read-only | none |
|
|
114
|
+
| 1 | safe write draft | config (default none) |
|
|
115
|
+
| 2 | file modification | **required** |
|
|
116
|
+
| 3 | shell / agent / network write | **required** |
|
|
117
|
+
| 4 | destructive / publish / deploy | **double approval** |
|
|
118
|
+
|
|
119
|
+
- No raw shell by default — only `shell_run_allowed_command` against an allowlist.
|
|
120
|
+
- Filesystem access limited to **allowed directories**; sensitive paths
|
|
121
|
+
(`~/.ssh`, `~/.aws`, `/etc`, …) are always blocked; symlink escapes are caught.
|
|
122
|
+
- Secrets live in an encrypted local vault and are **redacted** from tool
|
|
123
|
+
output and the audit log.
|
|
124
|
+
- Generated/installed skills are **disabled by default** until you review them.
|
|
125
|
+
|
|
126
|
+
Full details: [SECURITY.md](SECURITY.md).
|
|
127
|
+
|
|
128
|
+
## Dashboard
|
|
129
|
+
|
|
130
|
+
A local-only dashboard (`http://127.0.0.1:8788`) shows status, the MCP endpoint
|
|
131
|
+
(with copy button), pending approvals, the audit log, skills (enable/disable),
|
|
132
|
+
projects, secret names, and coding agents.
|
|
133
|
+
|
|
134
|
+
## Skills
|
|
135
|
+
|
|
136
|
+
Skills are the unit of extension. Layout:
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
skills/<name>/
|
|
140
|
+
skill.json # manifest: permissions + risk + tool schemas
|
|
141
|
+
README.md LICENSE CHANGELOG.md
|
|
142
|
+
src/index.ts # defineSkill({...})
|
|
143
|
+
tests/index.test.ts
|
|
144
|
+
examples/
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Manage them with `skill_list/info/enable/disable/run/validate/...` tools or the
|
|
148
|
+
CLI (`localant skills ...`). See [docs/skills.md](docs/skills.md).
|
|
149
|
+
|
|
150
|
+
### How to create a skill
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { defineSkill, z } from "@LocalAnt/skill-sdk";
|
|
154
|
+
|
|
155
|
+
export default defineSkill({
|
|
156
|
+
name: "hello-world",
|
|
157
|
+
tools: {
|
|
158
|
+
hello: {
|
|
159
|
+
description: "Say hello",
|
|
160
|
+
riskLevel: 0,
|
|
161
|
+
inputSchema: z.object({ name: z.string() }),
|
|
162
|
+
handler: async ({ name }) => ({ content: `Hello ${name}` }),
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### How to generate a skill from ChatGPT
|
|
169
|
+
|
|
170
|
+
> "Create a skill named `qiita-private-post` that posts private Qiita articles
|
|
171
|
+
> using a QIITA_TOKEN secret."
|
|
172
|
+
|
|
173
|
+
ChatGPT calls `skill_generate_from_prompt`. The gateway scaffolds the manifest,
|
|
174
|
+
README, source and tests, **infers permissions**, sets it **disabled**, and runs
|
|
175
|
+
validation. You review permissions in the dashboard, then `skill_enable` (which
|
|
176
|
+
requires approval). See [docs/skills.md](docs/skills.md).
|
|
177
|
+
|
|
178
|
+
## How to connect Claude Code
|
|
179
|
+
|
|
180
|
+
Enable an agent in config (`codingAgents.claude-code.enabled = true`), register a
|
|
181
|
+
project, then:
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
coding_agent_plan(agent:"claude-code", projectId:"my-app", task:"Plan SEO improvements")
|
|
185
|
+
# review the plan, approve, then:
|
|
186
|
+
coding_agent_start_task(agent:"claude-code", projectId:"my-app", task:"Implement the plan")
|
|
187
|
+
# creates a work branch, runs the agent, then:
|
|
188
|
+
coding_agent_get_diff(taskId) · coding_agent_run_validation(projectId)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Execution is risk-3 (approval required), runs on a fresh branch, warns on a dirty
|
|
192
|
+
tree, and is followed by diff + validation. See [docs/coding-agents.md](docs/coding-agents.md).
|
|
193
|
+
|
|
194
|
+
## Codex example
|
|
195
|
+
|
|
196
|
+
Same flow with `agent:"codex"` once `codingAgents.codex.enabled = true` and the
|
|
197
|
+
`codex` CLI is on PATH.
|
|
198
|
+
|
|
199
|
+
## Article publishing
|
|
200
|
+
|
|
201
|
+
- **Zenn**: GitHub-repo method — writes `articles/<slug>.md` with
|
|
202
|
+
`published:false`, can open a PR branch. (`zenn_*`)
|
|
203
|
+
- **Qiita**: official API with `QIITA_TOKEN` from the vault; private-first.
|
|
204
|
+
(`qiita_*`)
|
|
205
|
+
- **note**: draft-first local files; publishing requires the note-mcp adapter.
|
|
206
|
+
(`note_*`)
|
|
207
|
+
|
|
208
|
+
Publish actions are **risk 4 (double approval)**. See [docs/articles.md](docs/articles.md).
|
|
209
|
+
|
|
210
|
+
## Browser automation
|
|
211
|
+
|
|
212
|
+
Playwright-based (optional peer dependency), using an **isolated profile** by
|
|
213
|
+
default. `browser_open/screenshot/extract_text/click/type/...` — all risk 3.
|
|
214
|
+
See [docs/browser.md](docs/browser.md).
|
|
215
|
+
|
|
216
|
+
## Android ADB
|
|
217
|
+
|
|
218
|
+
`adb_list_devices/screenshot/tap/swipe/input_text/logcat/install_apk/...`.
|
|
219
|
+
Input/installs are risk 3 and audited. See [docs/adb.md](docs/adb.md).
|
|
220
|
+
|
|
221
|
+
## OpenClaw adapter
|
|
222
|
+
|
|
223
|
+
`openclaw_status/list_skills/run_skill/list_sessions/...` — bridges to a local
|
|
224
|
+
`openclaw` CLI if installed, otherwise returns clear install guidance. Every call
|
|
225
|
+
flows through the gateway's permission + approval + audit pipeline.
|
|
226
|
+
|
|
227
|
+
## Desktop Commander adapter
|
|
228
|
+
|
|
229
|
+
`desktop_commander_status/list_tools/run_tool` — gated bridge; tools are never
|
|
230
|
+
exposed unmediated.
|
|
231
|
+
|
|
232
|
+
## Existing MCP bridge
|
|
233
|
+
|
|
234
|
+
Register downstream MCP servers (`mcp_server_register/list/status/...`) to bundle
|
|
235
|
+
them behind the gateway's safety pipeline.
|
|
236
|
+
|
|
237
|
+
## CLI
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
localant setup | start | stop | restart | status | doctor | update | uninstall
|
|
241
|
+
localant tunnel status
|
|
242
|
+
localant dashboard | logs
|
|
243
|
+
localant approvals list | approve <id> [--session] | deny <id>
|
|
244
|
+
localant skills list | info <name> | enable <name> | disable <name> | install <git-url> | validate <name> | publish <name>
|
|
245
|
+
localant projects list | add <path> [--name <n>] | remove <id>
|
|
246
|
+
localant secrets set <name> [value] | list | remove <name>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Architecture
|
|
250
|
+
|
|
251
|
+
A pnpm + TypeScript monorepo with project references:
|
|
252
|
+
|
|
253
|
+
| Package | Responsibility |
|
|
254
|
+
|---------|----------------|
|
|
255
|
+
| `shared` | config schema, paths, risk model, redaction, types, logger |
|
|
256
|
+
| `gateway` | stores, security guards, managers, tool registry, execution pipeline |
|
|
257
|
+
| `mcp` | Streamable HTTP `/mcp`, auth, dashboard API |
|
|
258
|
+
| `dashboard` | self-contained local dashboard |
|
|
259
|
+
| `cli` | `setup`/`start`/`doctor`/… commands |
|
|
260
|
+
| `skill-sdk` | `defineSkill` for external skill authors |
|
|
261
|
+
|
|
262
|
+
See [docs/architecture.md](docs/architecture.md).
|
|
263
|
+
|
|
264
|
+
## FAQ
|
|
265
|
+
|
|
266
|
+
- **Does ChatGPT get a raw shell?** No. Only allowlisted commands run without
|
|
267
|
+
approval; anything else needs an explicit local approval.
|
|
268
|
+
- **Where is my config?** `~/Library/Application Support/LocalAnt` (macOS),
|
|
269
|
+
`~/.config/LocalAnt` (Linux), `%APPDATA%/LocalAnt` (Windows).
|
|
270
|
+
- **Do I need Claude Code/Codex/adb/Playwright?** Only for those specific tool
|
|
271
|
+
families; they degrade gracefully with install guidance.
|
|
272
|
+
- **Is the tunnel safe?** A public tunnel exposes the gateway; the auth token is
|
|
273
|
+
required, the dashboard warns you, and you should stop the tunnel when idle.
|
|
274
|
+
|
|
275
|
+
## Troubleshooting
|
|
276
|
+
|
|
277
|
+
`localant doctor` diagnoses your environment. More in
|
|
278
|
+
[docs/troubleshooting.md](docs/troubleshooting.md).
|
|
279
|
+
|
|
280
|
+
## How to uninstall
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
localant uninstall # prints steps
|
|
284
|
+
localant uninstall --purge # also deletes the config/data directory
|
|
285
|
+
npm uninstall -g localant
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## License
|
|
289
|
+
|
|
290
|
+
MIT — see [LICENSE](LICENSE).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
`LocalAnt` performs operations on your local machine on behalf of a
|
|
4
|
+
remote model (ChatGPT). Security is the top design priority. This document
|
|
5
|
+
describes the threat model and the controls that mitigate it.
|
|
6
|
+
|
|
7
|
+
## Threat model
|
|
8
|
+
|
|
9
|
+
| Actor / vector | Risk | Mitigation |
|
|
10
|
+
|----------------|------|------------|
|
|
11
|
+
| ChatGPT requests a destructive action | High | Risk levels + local approval queue; ChatGPT confirmation never trusted alone |
|
|
12
|
+
| Prompt-injected ChatGPT tries to read secrets/credentials | High | Secret vault (encrypted), redaction, sensitive-path blocklist |
|
|
13
|
+
| Path traversal / symlink escape | High | `PathGuard` resolves realpaths and re-checks allowlist + blocklist |
|
|
14
|
+
| Shell injection / command chaining | High | `CommandGuard` rejects pipes/redirection/substitution; allowlist prefix match; hard blocklist |
|
|
15
|
+
| Public tunnel exposure | Medium | Mandatory auth token; dashboard warnings; tunnel is opt-out |
|
|
16
|
+
| Malicious third-party skill | Medium | Skills disabled by default; per-skill permission manifest; isolated subprocess execution; only declared secrets injected |
|
|
17
|
+
| Secret leakage to logs/responses | Medium | Deep redaction of known secret values + token-shaped strings |
|
|
18
|
+
|
|
19
|
+
## Default deny
|
|
20
|
+
|
|
21
|
+
Nothing is permitted unless explicitly allowed:
|
|
22
|
+
|
|
23
|
+
- **Filesystem**: only paths inside `security.allowedDirectories`. Sensitive
|
|
24
|
+
paths (`~/.ssh`, `~/.gnupg`, `~/.aws`, `~/.config/gcloud`, Keychains, `/etc`,
|
|
25
|
+
`/var`, `/System`, `C:\Windows`, …) are always denied — even via symlink.
|
|
26
|
+
- **Shell**: no raw shell. `shell_run_allowed_command` only accepts commands
|
|
27
|
+
matching the allowlist; pipes, redirection, chaining, and command
|
|
28
|
+
substitution are rejected. A hard blocklist (`sudo`, `rm -rf`, `dd`, `mkfs`,
|
|
29
|
+
`chmod 777`, `ssh`, `shutdown`, …) applies even to approved commands.
|
|
30
|
+
- **Network/secrets/browser/adb/git/agent**: per-skill permission modes; tools
|
|
31
|
+
default to the least-privilege option.
|
|
32
|
+
|
|
33
|
+
## Risk levels & approval
|
|
34
|
+
|
|
35
|
+
| Risk | Meaning | Approval |
|
|
36
|
+
|------|---------|----------|
|
|
37
|
+
| 0 | read-only | none |
|
|
38
|
+
| 1 | safe write draft | configurable (`approveRisk1`, default off) |
|
|
39
|
+
| 2 | file modification | single approval |
|
|
40
|
+
| 3 | shell / agent / network write | single approval |
|
|
41
|
+
| 4 | destructive / publish / deploy | **double approval** |
|
|
42
|
+
|
|
43
|
+
Approvals are managed **locally** (dashboard, CLI `approvals`, or the
|
|
44
|
+
`approval_*` MCP tools). A risk-2+ tool call returns `approvalRequired` until a
|
|
45
|
+
human approves it; once-approvals are consumed after a single use.
|
|
46
|
+
|
|
47
|
+
## Filesystem safety
|
|
48
|
+
|
|
49
|
+
- Allowed-directory allowlist + sensitive-path blocklist.
|
|
50
|
+
- Path traversal (`..`) and symlink traversal prevention (realpath re-check).
|
|
51
|
+
- Backup-before-write for modifications/deletes; `fs_list_backups` /
|
|
52
|
+
`fs_restore_backup`.
|
|
53
|
+
- Max file size and binary-file guard on reads; draft writes refuse overwrite.
|
|
54
|
+
|
|
55
|
+
## Shell safety
|
|
56
|
+
|
|
57
|
+
- Allowlist prefix matching; pipeline/redirection/chaining/substitution rejected.
|
|
58
|
+
- Hard blocklist enforced even after approval.
|
|
59
|
+
- No shell interpreter — validated commands are split to argv and executed
|
|
60
|
+
directly with a timeout and output cap.
|
|
61
|
+
|
|
62
|
+
## Secret safety
|
|
63
|
+
|
|
64
|
+
- Secrets stored in an AES-256-GCM encrypted vault keyed from the local token.
|
|
65
|
+
- Listing returns **names only**; values are never displayed.
|
|
66
|
+
- Tool output and audit entries are deep-redacted for known secret values and
|
|
67
|
+
token-shaped strings.
|
|
68
|
+
- Skills receive only the secret values they declare in their manifest, passed
|
|
69
|
+
to an isolated subprocess — never the vault itself.
|
|
70
|
+
|
|
71
|
+
## Skill safety
|
|
72
|
+
|
|
73
|
+
- Generated and git-installed skills are saved **disabled**.
|
|
74
|
+
- Each skill ships a permission manifest and risk level, surfaced before enable.
|
|
75
|
+
- Skills execute in an isolated Node subprocess.
|
|
76
|
+
- `skill_validate` checks manifest + required files before enabling.
|
|
77
|
+
|
|
78
|
+
## Audit
|
|
79
|
+
|
|
80
|
+
Every tool call is appended to `audit/audit.jsonl` with timestamp, tool, caller,
|
|
81
|
+
risk, redacted input/output summaries, approval result, duration, and error.
|
|
82
|
+
|
|
83
|
+
## Reporting vulnerabilities
|
|
84
|
+
|
|
85
|
+
Please open a private security advisory on the repository or email the
|
|
86
|
+
maintainers rather than filing a public issue. Include reproduction steps and
|
|
87
|
+
affected versions. We aim to acknowledge within a few days.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MIT License — see repository root LICENSE.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# hello-world
|
|
2
|
+
|
|
3
|
+
A minimal example local skill for `LocalAnt`.
|
|
4
|
+
|
|
5
|
+
## Permissions
|
|
6
|
+
None. This skill only echoes a greeting — no filesystem, shell, network, or secret access.
|
|
7
|
+
|
|
8
|
+
- risk level: 0 (read-only)
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
Once enabled, ask ChatGPT:
|
|
12
|
+
|
|
13
|
+
> Use the hello-world skill to greet "Yuga".
|
|
14
|
+
|
|
15
|
+
ChatGPT calls `skill_run` with `{ name: "hello-world", tool: "hello", input: { name: "Yuga" } }`.
|
|
16
|
+
|
|
17
|
+
## Develop
|
|
18
|
+
```bash
|
|
19
|
+
pnpm test # runs tests/index.test.ts
|
|
20
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "name": "Yuga" }
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hello-world",
|
|
3
|
+
"displayName": "Hello World",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "A minimal example local skill that greets a name.",
|
|
6
|
+
"author": "LocalAnt",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"entry": "src/index.ts",
|
|
9
|
+
"riskLevel": 0,
|
|
10
|
+
"permissions": {
|
|
11
|
+
"filesystem": { "mode": "none", "allowedDirectories": [] },
|
|
12
|
+
"shell": { "mode": "none", "allowedCommands": [] },
|
|
13
|
+
"network": { "mode": "none", "allowedHosts": [] },
|
|
14
|
+
"secrets": [],
|
|
15
|
+
"browser": "none",
|
|
16
|
+
"adb": "none",
|
|
17
|
+
"git": "none",
|
|
18
|
+
"agent": "none"
|
|
19
|
+
},
|
|
20
|
+
"tools": [
|
|
21
|
+
{
|
|
22
|
+
"name": "hello",
|
|
23
|
+
"description": "Say hello to a name.",
|
|
24
|
+
"riskLevel": 0,
|
|
25
|
+
"inputSchema": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"properties": { "name": { "type": "string" } },
|
|
28
|
+
"required": ["name"]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineSkill, z } from "@localant/skill-sdk";
|
|
2
|
+
|
|
3
|
+
export default defineSkill({
|
|
4
|
+
name: "hello-world",
|
|
5
|
+
displayName: "Hello World",
|
|
6
|
+
description: "A minimal example local skill.",
|
|
7
|
+
version: "0.1.0",
|
|
8
|
+
tools: {
|
|
9
|
+
hello: {
|
|
10
|
+
description: "Say hello to a name.",
|
|
11
|
+
riskLevel: 0,
|
|
12
|
+
inputSchema: z.object({ name: z.string() }),
|
|
13
|
+
handler: async ({ name }, ctx) => {
|
|
14
|
+
ctx.log(`greeting ${name}`);
|
|
15
|
+
return { content: `Hello, ${name}! 👋 (from your local PC)` };
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import skill from "../src/index";
|
|
3
|
+
|
|
4
|
+
describe("hello-world skill", () => {
|
|
5
|
+
it("exposes the hello tool", () => {
|
|
6
|
+
expect(skill.name).toBe("hello-world");
|
|
7
|
+
expect(skill.tools.hello).toBeDefined();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("greets a name", async () => {
|
|
11
|
+
const ctx = { getSecret: async () => undefined, workspaceDir: ".", log: () => {} };
|
|
12
|
+
const out = (await skill.tools.hello.handler({ name: "Yuga" }, ctx)) as { content: string };
|
|
13
|
+
expect(out.content).toContain("Hello, Yuga!");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("validates input", () => {
|
|
17
|
+
expect(() => skill.tools.hello.inputSchema.parse({})).toThrow();
|
|
18
|
+
});
|
|
19
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "localant",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "LocalAnt — Use ChatGPT as the brain and your local computer as the hands. A safe, permissioned local MCP Gateway for ChatGPT.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"localant": "packages/cli/dist/bin.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"packages/*/dist/**",
|
|
13
|
+
"packages/*/package.json",
|
|
14
|
+
"examples/skills/**",
|
|
15
|
+
"README.md",
|
|
16
|
+
"SECURITY.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=20"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -b",
|
|
24
|
+
"clean": "tsc -b --clean && rimraf packages/*/dist",
|
|
25
|
+
"dev": "tsc -b --watch",
|
|
26
|
+
"typecheck": "tsc -b --noEmit false",
|
|
27
|
+
"lint": "eslint .",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"test:watch": "vitest",
|
|
30
|
+
"validate": "pnpm build && pnpm test",
|
|
31
|
+
"start": "node packages/cli/dist/bin.js start",
|
|
32
|
+
"setup": "node packages/cli/dist/bin.js setup"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"chatgpt",
|
|
36
|
+
"mcp",
|
|
37
|
+
"model-context-protocol",
|
|
38
|
+
"local-first",
|
|
39
|
+
"gateway",
|
|
40
|
+
"skills",
|
|
41
|
+
"claude-code",
|
|
42
|
+
"codex",
|
|
43
|
+
"automation",
|
|
44
|
+
"openclaw",
|
|
45
|
+
"localant"
|
|
46
|
+
],
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@localant/gateway": "workspace:*",
|
|
49
|
+
"@localant/mcp": "workspace:*",
|
|
50
|
+
"@localant/shared": "workspace:*",
|
|
51
|
+
"@localant/skill-sdk": "workspace:*",
|
|
52
|
+
"@types/express": "^5.0.0",
|
|
53
|
+
"@types/node": "^22.10.0",
|
|
54
|
+
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
55
|
+
"@typescript-eslint/parser": "^8.18.0",
|
|
56
|
+
"eslint": "^9.17.0",
|
|
57
|
+
"rimraf": "^6.0.1",
|
|
58
|
+
"tsx": "^4.19.2",
|
|
59
|
+
"typescript": "^5.7.2",
|
|
60
|
+
"vitest": "^2.1.8"
|
|
61
|
+
},
|
|
62
|
+
"packageManager": "pnpm@11.5.1"
|
|
63
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
|