SBAIChat, plan and agent assistance in VS Code — powered by a model running on your own phone.
This extension connects VS Code to the SBAI server, an AI model running on an Android device over your local WiFi. The device holds the model and does the inference; VS Code is the client — a chat panel in the activity bar with streaming answers, editor-context commands and an agent mode that can read and edit files. Nothing leaves your network. There is no cloud account, no API key and no usage bill: your hardware is the compute, and your repository is the only place your code goes.
Features
Requirements
Getting started1. Start the server on the deviceInstall the SBAI server APK on your Android device, launch it and start the server. Note the device's IP address under Settings → About phone → Status → IP address. There is no prebuilt APK yet — build it from source with the step-by-step guide in SBAI → Android App.
2. Install this extensionInstall SBAI from the Visual Studio Marketplace, or from the command line:
3. Point it at the phoneSet the endpoint to your phone:
4. Pair, connect, chatRun SBAI: Pair with Device... and enter the code the phone shows. Pairing exchanges the code for a bearer token, stored in VS Code's secret storage. Connect then turns green once the device answers a probe, and the conversation becomes available. Controls come alive in that order on purpose: Pair devices is the only live control to begin with, Connect and Manage… need a stored token, and the chat itself needs a reachable device. The chat panelModes
Switch with SBAI: Select Mode.... The mode is applied at send time rather than stored in the history, so changing it affects the next answer without clearing the chat. Tabs
Each tab carries its own history, transcript, attached images, in-flight request and
mode, so several can run at once — a tab behind another keeps streaming and shows a
green dot until it is done. A tab is named after its mode ( Closing every tab is allowed, and leaves a New session button rather than a tab that reappears. Sessions live in memory only: they survive the view being hidden, but not a window reload. ImagesPaste or attach an image into the composer. It is sent inline as a data URI with a marker telling the device where in the conversation the picture belongs. ModelsThe panel shows the models on the phone, not a catalogue of everything that exists: an empty device means an empty list until you send it something.
Large transfers can be slow over WiFi; sending a model writes it to the phone's storage and is not resumable. Workspace index and assetsTwo folders under
|
| Field | Read from |
|---|---|
submodules |
.gitmodules — name, vendored path and URL |
repositories |
those URLs, plus repository links found in any README.md / README.txt |
wikis |
links containing /wiki in the same READMEs |
toolchains |
the files that actually pin a version (NDK, SDK platform, Gradle, Node, the VS Code engine), each with the file it was read from |
Entries added by hand are marked "source": "manual" and survive a rebuild.
.sbai/assets/
Media that belongs to the workspace: .svg .png .bmp .wav .flac .mp3 .mp4,
kept next to the code that uses it and versioned with it. SBAI: Assets... creates one.
Reference text for the prompt
For material that should be pasted into the prompt rather than indexed, put a
sbai/knowledge.json — or sbai/knowledge.txt — at the root of the open folder:
{
"entries": [
{
"id": "build",
"tags": ["build", "cmake", "ninja"],
"text": "Android builds with gradlew.bat -p SBAI/android assembleDebug."
}
]
}
The resident model runs a 4096-token context, so the file is selected from, not dumped: entries matching the question are included in score order until roughly 6000 characters are used, and if nothing matches the file is included only when it fits that budget anyway.
Settings
| Setting | Type | Default | Description |
|---|---|---|---|
sbai.endpoint |
string |
http://192.168.1.50:8080/completions |
SBAI server completion endpoint |
sbai.model |
string |
sbai-default |
Reserved — SBAI v1 keeps a single model resident |
sbai.maxTokens |
number |
2048 |
Maximum tokens to generate. v1 carries no finish reason, so a small cap truncates a long plan silently |
sbai.temperature |
number |
0.7 |
Sampling temperature |
sbai.timeout |
number |
60000 |
Request timeout (ms) — how long to wait for a response at all (connecting, pairing, transferring) |
sbai.stallTimeout |
number |
300000 |
Idle timeout (ms) during a generation, reset on every token — only a device that has stopped talking is cut off |
sbai.toolStepLimit |
number |
12 |
Tool round-trips one Agent-mode message may take |
sbai.stream |
boolean |
true |
Enable raw token streaming |
sbai.autoConnect |
boolean |
false |
Connect on startup |
sbai.openOnStartup |
boolean |
true |
Reveal the SBAI chat when a window opens |
sbai.modelsDirectory |
string |
"" |
Where GGUFs are cached before being pushed to the device; empty uses the extension's global storage |
sbai.ramBudgetGb |
number |
0 |
RAM one model may use, in GB. 0 derives it from the device |
sbai.mode |
string |
ask |
Mode a new tab starts in. Each tab keeps its own |
Commands
| Command | ID |
|---|---|
| SBAI: Open Chat | sbai.openChat |
| SBAI: Clear Chat | sbai.clearChat |
| SBAI: Ask About Selection | sbai.askSelection |
| SBAI: Explain Code | sbai.explain |
| SBAI: Refactor Code | sbai.refactor |
| SBAI: Generate Tests | sbai.generateTests |
| SBAI: Select Mode... | sbai.selectMode |
| SBAI: Connect | sbai.connect |
| SBAI: Disconnect | sbai.disconnect |
| SBAI: Find Device... | sbai.findDevice |
| SBAI: Pair with Device... | sbai.pairDevice |
| SBAI: Forget Device | sbai.forgetDevice |
| SBAI: Re-check Device | sbai.refreshDevice |
| SBAI: Download & Send Model... | sbai.downloadModel |
| SBAI: Add Model from URL... | sbai.addModelFromUrl |
| SBAI: Models on Phone... | sbai.listModels |
| SBAI: Send Model to Device | sbai.sendModel |
| SBAI: Activate Model | sbai.activateModel |
| SBAI: Delete Model from Device | sbai.deleteModel |
| SBAI: Set RAM Budget for Models | sbai.setRamBudget |
| SBAI: Add Knowledge... | sbai.addKnowledge |
| SBAI: Knowledges... | sbai.knowledges |
| SBAI: Update Knowledges | sbai.updateKnowledges |
| SBAI: Assets... | sbai.assets |
| SBAI: Manage... | sbai.manage |
Staying in sync
HTTP has no connection to watch, so neither side can be told the other has gone. Both sides therefore rely on a beat defined in Protocol §12.4:
- The extension sends one authenticated request every 5 seconds for as long as it holds
a token.
GET /modelsis the request, because it is the cheapest one that passes the auth gate and refreshes the model picker on the way. - The phone drops a token it has not seen for 60 seconds — twelve missed beats.
- A
401on a beat means the device has forgotten this client: the token is dropped, the panel dims back to "Not paired", and the offer to pair again appears once.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
ECONNREFUSED |
Server not running, or the wrong port | Start SBAI on the phone and check the port |
| Request times out | Different WiFi network, or a firewall in the way | Put both devices on the same network |
| Empty stream | Streaming disabled on the server | Set sbai.stream to false, or update the server |
| "Pairing required" | The device has no token for this client | Run SBAI: Pair with Device... |
| Models list is empty | Nothing has been sent to the phone yet | Send a model with Download & Send Model... |
| SBAI icon missing | The window has not loaded the extension | Reload the window (Developer: Reload Window) |
SecurityError / UnauthorizedAccess when building on Windows |
PowerShell blocks npm.ps1 |
Use npm.cmd (or Set-ExecutionPolicy -Scope CurrentUser RemoteSigned) |
Verify the device is reachable
Any HTTP response — including a 400 — means the server is up:
curl -s -o /dev/null -w "%{http_code}\n" -X POST http://192.168.1.50:8080/completions \
-H "Content-Type: application/json" -d '{"messages":[]}'
The API is documented in full in
PROTOCOL.md, including the
curl and PowerShell equivalents.
Develop from source
git clone https://github.com/sibjor/SBAI_VSCode
cd SBAI_VSCode
npm install
npm run build # or: npm run watch
npm test
npm run lint
Press F5 to launch an Extension Development Host. To run without the phone, start the
bundled mock server and point sbai.endpoint at it:
npm run mock # http://127.0.0.1:8080
npm run mock -- --delay 60 --port 9000
Connect should turn green (the reachability probe gets the expected 400) and a chat
message should stream back token by token. The mock server is a test tool only
(tools/mock-server.js); the real server lives in
sibjor/SBAI.
Documentation
- PROTOCOL.md — the frozen wire contract, shared byte-for-byte with the SBAI server repository.
- ARCHITECTURE.md — system design and data flow.
- ROADMAP.md — planned phases and milestones.
- TODO.md — actionable task checklist.