adom-vscode
Public Made by Adomby adom
Drive VS Code from your AI — a CLI + extension that lets Claude Code, Codex, and any other process open files, switch modes, paste screenshots, view live AI session stats, and run any VS Code command via a local HTTP API. Pre-installed in every Adom container.
adom-vscode — VS Code Extension + Rust CLI
Context
Docker processes (shotlog, gallia, Claude Code) need to control VS Code (code-server) programmatically — open files, reveal folders, search/install extensions, start new Claude Code chats. The Hydrogen workspace API only controls the outer shell; VS Code is an iframe running code-server with its own API. A VS Code extension inside code-server exposes a local HTTP server, and a Rust CLI wraps those calls for the AI.
Source lives in its own repo adom-inc/adom-vscode. Pre-built binary + VSIX attached to GitHub Releases. gallia/install.mjs downloads them — no Rust toolchain needed on user containers.
Architecture
Claude Code / scripts / shotlog
↓ runs CLI
adom-vscode open /foo/bar.png
↓ HTTP POST to localhost:8821
Adom VS Code Extension (inside code-server)
↓ vscode.* API
VS Code UI
File Structure
Repo: adom-inc/adom-vscode
/home/adom/project/adom-vscode/
├── extension/
│ ├── package.json — Extension manifest
│ ├── src/extension.ts — HTTP server + route handlers
│ ├── tsconfig.json — TS config (IDE only, esbuild compiles)
│ └── .vscodeignore — Exclude src/ from VSIX
├── cli/
│ ├── Cargo.toml — Rust CLI
│ └── src/main.rs — CLI entry (clap, raw HTTP client)
├── SKILL.md — Claude Code skill (CLI usage, endpoints, modes)
├── COMMANDS.md — Full VS Code + extension command reference
├── ARCHITECTURE.md — This plan file, saved permanently
├── README.md — Project overview, links to ARCHITECTURE.md
├── build.sh — Local build + install (dev only)
└── .gitignore
Distribution (GitHub Releases on adom-inc/adom-vscode):
adom-vscode— single pre-built Linux x86_64 binary (embeds VSIX + SKILL.md viainclude_bytes!/include_str!)
Gallia integration — install.mjs downloads the one binary, then self-installs:
gh release download→/usr/local/bin/adom-vscodeadom-vscode install-extension(extracts embedded VSIX, installs into code-server)adom-vscode skills install(writes embedded SKILL.md to~/.claude/skills/)
Extension (TypeScript)
Port: 8821 (127.0.0.1 only)
Endpoints
| Method | Path | Body | VS Code API |
|---|---|---|---|
| GET | /health |
— | — |
| POST | /open |
{"path":"..."} |
showTextDocument(uri) |
| POST | /reveal |
{"path":"..."} |
executeCommand('revealInExplorer') |
| POST | /preview-markdown |
{"path":"..."} |
executeCommand('markdown.showPreview') |
| POST | /extensions/search |
{"query":"..."} |
executeCommand('workbench.extensions.search') |
| POST | /extensions/install |
{"id":"..."} |
executeCommand('workbench.extensions.installExtension') |
| POST | /claude/new |
{} |
executeCommand('claude-vscode.newConversation') |
| POST | /command |
{"command":"...","args":[]} |
executeCommand(cmd, ...args) |
| POST | /notify |
{"message":"...","level":"info"} |
showInformationMessage() |
| POST | /mode/claudecode |
{} |
See below — enters Claude Code-only mode |
| POST | /mode/reset |
{} |
Restores default VS Code layout |
Claude Code-only mode (POST /mode/claudecode)
Strips VS Code down to just a Claude Code chat. For onboarding new users.
The handler runs these VS Code commands in sequence:
workbench.action.closeAllEditors— clear all tabsworkbench.action.closeSidebar— hide file explorerworkbench.action.closePanel— hide terminal/bottom panelworkbench.action.toggleActivityBarVisibility— hide left icon strip (check if visible first via config)workbench.action.toggleStatusBarVisibility— hide bottom status barclaude-vscode.editor.open— open Claude Code in full-width editor tab
Result: clean full-screen AI chat, nothing else.
POST /mode/reset reverses it — shows activity bar, status bar, sidebar.
URL-based auto-trigger (?mode=claudecode)
Code-server persists all URL query params to ~/.local/share/code-server/coder.json under the query key. When a user visits https://slug.adom.cloud/?mode=claudecode, that file becomes:
{ "query": { "folder": "...", "mode": "claudecode" } }
On extension activation, read that file and check query.mode:
const coderSettings = JSON.parse(fs.readFileSync(
path.join(os.homedir(), '.local/share/code-server/coder.json'), 'utf-8'
));
if (coderSettings.query?.mode === 'claudecode') {
await enterClaudeCodeMode();
}
No temp files, no middleware, no proxy changes. Just the URL param and the extension.
Key details
activationEvents: ["*"]— starts with code-server- Node.js
httpmodule (built into extension host), zero runtime deps - CORS headers, EADDRINUSE retry,
context.subscriptionscleanup - On activate: read
~/.local/share/code-server/coder.jsonforquery.modeauto-trigger - Build:
esbuildbundles to singleout/extension.js(~3KB) - Package:
npx @vscode/vsce package --no-dependencies
Rust CLI
Binary: adom-vscode
# File operations
adom-vscode open /path/to/file.png
adom-vscode reveal /path/to/folder/
adom-vscode preview /path/to/README.md
# Extensions
adom-vscode extensions search "python"
adom-vscode extensions install ms-python.python
# Claude Code
adom-vscode claude new
# UI modes
adom-vscode mode claudecode
adom-vscode mode reset
# Generic VS Code command (escape hatch)
adom-vscode command workbench.action.toggleSidebarVisibility
adom-vscode command workbench.action.reloadWindow
# Notifications
adom-vscode notify "Build complete!" --level info
# Skill management
adom-vscode skills install
adom-vscode skills list
# Extension management
adom-vscode install-extension # writes embedded VSIX to /tmp, installs into code-server
# Health
adom-vscode health
AI-oriented output
OK: Opened /home/adom/project/README.md in VS Code tab.
OK: Revealed /home/adom/project/src/ in VS Code Explorer sidebar.
OK: Opened new Claude Code conversation in VS Code.
ERROR: Cannot connect to adom-vscode extension on port 8821.
Hint: The extension may need a window reload. Install with: bash /home/adom/project/adom-vscode/build.sh
Deps: clap, serde_json only. Raw TCP HTTP client (no reqwest).
Gallia Integration
install.mjs addition (~line 136, after adom-cli install)
// ── Install adom-vscode (binary + extension from GitHub Releases) ─────
console.log('\n1e. Installing adom-vscode...');
{
try {
execSync(
'gh release download --repo adom-inc/adom-vscode --pattern "adom-vscode" --output /usr/local/bin/adom-vscode --clobber',
{ stdio: 'ignore' }
);
execSync('sudo chmod +x /usr/local/bin/adom-vscode', { stdio: 'ignore' });
console.log(' ✓ adom-vscode CLI installed');
} catch { console.log(' ⚠ Could not download adom-vscode CLI'); }
// Self-install extension + skill (both embedded in binary)
try {
execSync('adom-vscode install-extension', { stdio: 'ignore' });
console.log(' ✓ adom-vscode extension installed');
} catch { console.log(' ⚠ Could not install adom-vscode extension'); }
try {
execSync('adom-vscode skills install', { stdio: 'ignore' });
console.log(' ✓ adom-vscode skills installed');
} catch { console.log(' ⚠ Could not install adom-vscode skills'); }
}
build.sh (dev only — for building locally before cutting a release)
cd extension && npm install && npx esbuild ... && npx @vscode/vsce package- Install VSIX into local code-server
cd ../cli && cargo build --release && sudo cp target/release/adom-vscode /usr/local/bin/
Releasing
cd /home/adom/project/adom-vscode
bash build.sh
gh release create v0.1.0 \
cli/target/release/adom-vscode \
--repo adom-inc/adom-vscode \
--title "v0.1.0" --notes "Initial release — single binary ships CLI + extension + skill"
Implementation Steps
- Create
extension/— package.json, tsconfig.json, .vscodeignore, src/extension.ts - Build + package VSIX, install into code-server
- Reload VS Code window, verify
curl http://127.0.0.1:8821/health - Test each endpoint with curl
- Create
cli/— Cargo.toml, src/main.rs - Build CLI, install to /usr/local/bin/
- Test:
adom-vscode health,adom-vscode open /path/to/file - Write SKILL.md + build.sh
- Add install.mjs hook
- Add row to main adom SKILL.md capabilities table
- Update shotlog filepath links to use
adom-vscode openinstead of code-server CLI directly
Verification
curl http://127.0.0.1:8821/health
adom-vscode open /home/adom/project/shotlog/data/test/shot-2026-03-28T13-43-30.png
adom-vscode reveal /home/adom/project/shotlog/data/test/
adom-vscode claude new
adom-vscode extensions search "python"
adom-vscode notify "Hello from adom-vscode!"
Critical Files
| File | Purpose |
|---|---|
/home/adom/project/adom-vscode/extension/src/extension.ts |
HTTP server + VS Code API handlers |
/home/adom/project/adom-vscode/extension/package.json |
Extension manifest |
/home/adom/project/adom-vscode/cli/src/main.rs |
Rust CLI |
/home/adom/project/adom-vscode/SKILL.md |
Claude Code skill (embedded in binary) |
/home/adom/project/adom-vscode/ARCHITECTURE.md |
This plan file |
/home/adom/project/adom-vscode/README.md |
Project overview |
/home/adom/project/adom-vscode/build.sh |
Build + install script |
/home/adom/gallia/install.mjs |
Add download hook (~line 136) |
# adom-vscode — VS Code Extension + Rust CLI
## Context
Docker processes (shotlog, gallia, Claude Code) need to control VS Code (code-server) programmatically — open files, reveal folders, search/install extensions, start new Claude Code chats. The Hydrogen workspace API only controls the outer shell; VS Code is an iframe running code-server with its own API. A VS Code extension inside code-server exposes a local HTTP server, and a Rust CLI wraps those calls for the AI.
Source lives in its own repo `adom-inc/adom-vscode`. Pre-built binary + VSIX attached to GitHub Releases. `gallia/install.mjs` downloads them — no Rust toolchain needed on user containers.
## Architecture
```
Claude Code / scripts / shotlog
↓ runs CLI
adom-vscode open /foo/bar.png
↓ HTTP POST to localhost:8821
Adom VS Code Extension (inside code-server)
↓ vscode.* API
VS Code UI
```
## File Structure
**Repo**: `adom-inc/adom-vscode`
```
/home/adom/project/adom-vscode/
├── extension/
│ ├── package.json — Extension manifest
│ ├── src/extension.ts — HTTP server + route handlers
│ ├── tsconfig.json — TS config (IDE only, esbuild compiles)
│ └── .vscodeignore — Exclude src/ from VSIX
├── cli/
│ ├── Cargo.toml — Rust CLI
│ └── src/main.rs — CLI entry (clap, raw HTTP client)
├── SKILL.md — Claude Code skill (CLI usage, endpoints, modes)
├── COMMANDS.md — Full VS Code + extension command reference
├── ARCHITECTURE.md — This plan file, saved permanently
├── README.md — Project overview, links to ARCHITECTURE.md
├── build.sh — Local build + install (dev only)
└── .gitignore
```
**Distribution** (GitHub Releases on adom-inc/adom-vscode):
- `adom-vscode` — single pre-built Linux x86_64 binary (embeds VSIX + SKILL.md via `include_bytes!`/`include_str!`)
**Gallia integration** — `install.mjs` downloads the one binary, then self-installs:
- `gh release download` → `/usr/local/bin/adom-vscode`
- `adom-vscode install-extension` (extracts embedded VSIX, installs into code-server)
- `adom-vscode skills install` (writes embedded SKILL.md to `~/.claude/skills/`)
## Extension (TypeScript)
### Port: 8821 (127.0.0.1 only)
### Endpoints
| Method | Path | Body | VS Code API |
|--------|------|------|-------------|
| GET | `/health` | — | — |
| POST | `/open` | `{"path":"..."}` | `showTextDocument(uri)` |
| POST | `/reveal` | `{"path":"..."}` | `executeCommand('revealInExplorer')` |
| POST | `/preview-markdown` | `{"path":"..."}` | `executeCommand('markdown.showPreview')` |
| POST | `/extensions/search` | `{"query":"..."}` | `executeCommand('workbench.extensions.search')` |
| POST | `/extensions/install` | `{"id":"..."}` | `executeCommand('workbench.extensions.installExtension')` |
| POST | `/claude/new` | `{}` | `executeCommand('claude-vscode.newConversation')` |
| POST | `/command` | `{"command":"...","args":[]}` | `executeCommand(cmd, ...args)` |
| POST | `/notify` | `{"message":"...","level":"info"}` | `showInformationMessage()` |
| POST | `/mode/claudecode` | `{}` | See below — enters Claude Code-only mode |
| POST | `/mode/reset` | `{}` | Restores default VS Code layout |
### Claude Code-only mode (`POST /mode/claudecode`)
Strips VS Code down to just a Claude Code chat. For onboarding new users.
The handler runs these VS Code commands in sequence:
1. `workbench.action.closeAllEditors` — clear all tabs
2. `workbench.action.closeSidebar` — hide file explorer
3. `workbench.action.closePanel` — hide terminal/bottom panel
4. `workbench.action.toggleActivityBarVisibility` — hide left icon strip (check if visible first via config)
5. `workbench.action.toggleStatusBarVisibility` — hide bottom status bar
6. `claude-vscode.editor.open` — open Claude Code in full-width editor tab
Result: clean full-screen AI chat, nothing else.
`POST /mode/reset` reverses it — shows activity bar, status bar, sidebar.
### URL-based auto-trigger (`?mode=claudecode`)
Code-server persists all URL query params to `~/.local/share/code-server/coder.json` under the `query` key. When a user visits `https://slug.adom.cloud/?mode=claudecode`, that file becomes:
```json
{ "query": { "folder": "...", "mode": "claudecode" } }
```
On extension activation, read that file and check `query.mode`:
```typescript
const coderSettings = JSON.parse(fs.readFileSync(
path.join(os.homedir(), '.local/share/code-server/coder.json'), 'utf-8'
));
if (coderSettings.query?.mode === 'claudecode') {
await enterClaudeCodeMode();
}
```
No temp files, no middleware, no proxy changes. Just the URL param and the extension.
### Key details
- `activationEvents: ["*"]` — starts with code-server
- Node.js `http` module (built into extension host), zero runtime deps
- CORS headers, EADDRINUSE retry, `context.subscriptions` cleanup
- On activate: read `~/.local/share/code-server/coder.json` for `query.mode` auto-trigger
- Build: `esbuild` bundles to single `out/extension.js` (~3KB)
- Package: `npx @vscode/vsce package --no-dependencies`
## Rust CLI
### Binary: `adom-vscode`
```
# File operations
adom-vscode open /path/to/file.png
adom-vscode reveal /path/to/folder/
adom-vscode preview /path/to/README.md
# Extensions
adom-vscode extensions search "python"
adom-vscode extensions install ms-python.python
# Claude Code
adom-vscode claude new
# UI modes
adom-vscode mode claudecode
adom-vscode mode reset
# Generic VS Code command (escape hatch)
adom-vscode command workbench.action.toggleSidebarVisibility
adom-vscode command workbench.action.reloadWindow
# Notifications
adom-vscode notify "Build complete!" --level info
# Skill management
adom-vscode skills install
adom-vscode skills list
# Extension management
adom-vscode install-extension # writes embedded VSIX to /tmp, installs into code-server
# Health
adom-vscode health
```
### AI-oriented output
```
OK: Opened /home/adom/project/README.md in VS Code tab.
OK: Revealed /home/adom/project/src/ in VS Code Explorer sidebar.
OK: Opened new Claude Code conversation in VS Code.
ERROR: Cannot connect to adom-vscode extension on port 8821.
Hint: The extension may need a window reload. Install with: bash /home/adom/project/adom-vscode/build.sh
```
### Deps: `clap`, `serde_json` only. Raw TCP HTTP client (no reqwest).
## Gallia Integration
### install.mjs addition (~line 136, after adom-cli install)
```javascript
// ── Install adom-vscode (binary + extension from GitHub Releases) ─────
console.log('\n1e. Installing adom-vscode...');
{
try {
execSync(
'gh release download --repo adom-inc/adom-vscode --pattern "adom-vscode" --output /usr/local/bin/adom-vscode --clobber',
{ stdio: 'ignore' }
);
execSync('sudo chmod +x /usr/local/bin/adom-vscode', { stdio: 'ignore' });
console.log(' ✓ adom-vscode CLI installed');
} catch { console.log(' ⚠ Could not download adom-vscode CLI'); }
// Self-install extension + skill (both embedded in binary)
try {
execSync('adom-vscode install-extension', { stdio: 'ignore' });
console.log(' ✓ adom-vscode extension installed');
} catch { console.log(' ⚠ Could not install adom-vscode extension'); }
try {
execSync('adom-vscode skills install', { stdio: 'ignore' });
console.log(' ✓ adom-vscode skills installed');
} catch { console.log(' ⚠ Could not install adom-vscode skills'); }
}
```
### build.sh (dev only — for building locally before cutting a release)
1. `cd extension && npm install && npx esbuild ... && npx @vscode/vsce package`
2. Install VSIX into local code-server
3. `cd ../cli && cargo build --release && sudo cp target/release/adom-vscode /usr/local/bin/`
### Releasing
```bash
cd /home/adom/project/adom-vscode
bash build.sh
gh release create v0.1.0 \
cli/target/release/adom-vscode \
--repo adom-inc/adom-vscode \
--title "v0.1.0" --notes "Initial release — single binary ships CLI + extension + skill"
```
## Implementation Steps
1. Create `extension/` — package.json, tsconfig.json, .vscodeignore, src/extension.ts
2. Build + package VSIX, install into code-server
3. Reload VS Code window, verify `curl http://127.0.0.1:8821/health`
4. Test each endpoint with curl
5. Create `cli/` — Cargo.toml, src/main.rs
6. Build CLI, install to /usr/local/bin/
7. Test: `adom-vscode health`, `adom-vscode open /path/to/file`
8. Write SKILL.md + build.sh
9. Add install.mjs hook
10. Add row to main adom SKILL.md capabilities table
11. Update shotlog filepath links to use `adom-vscode open` instead of code-server CLI directly
## Verification
```bash
curl http://127.0.0.1:8821/health
adom-vscode open /home/adom/project/shotlog/data/test/shot-2026-03-28T13-43-30.png
adom-vscode reveal /home/adom/project/shotlog/data/test/
adom-vscode claude new
adom-vscode extensions search "python"
adom-vscode notify "Hello from adom-vscode!"
```
## Critical Files
| File | Purpose |
|------|---------|
| `/home/adom/project/adom-vscode/extension/src/extension.ts` | HTTP server + VS Code API handlers |
| `/home/adom/project/adom-vscode/extension/package.json` | Extension manifest |
| `/home/adom/project/adom-vscode/cli/src/main.rs` | Rust CLI |
| `/home/adom/project/adom-vscode/SKILL.md` | Claude Code skill (embedded in binary) |
| `/home/adom/project/adom-vscode/ARCHITECTURE.md` | This plan file |
| `/home/adom/project/adom-vscode/README.md` | Project overview |
| `/home/adom/project/adom-vscode/build.sh` | Build + install script |
| `/home/adom/gallia/install.mjs` | Add download hook (~line 136) |