owo-local
Connect Pi to local and self-hosted OpenAI-compatible LLM servers with configurable URL and optional API key
Package details
Install owo-local from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:owo-local- Package
owo-local- Version
0.2.1- Published
- Aug 18, 2026
- Downloads
- 445/mo · 8/wk
- Author
- justar_96
- License
- MIT
- Types
- extension
- Size
- 49 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
owo-local
owo-local is a Pi package that connects Pi to OpenAI-compatible local and
self-hosted model servers. It supports interactive login, bearer or keyless
authentication, live /models discovery, offline fallback catalogs, streaming,
reasoning toggles, and configurable model limits.
This repository also contains an example SGLang deployment for
orcarouter/Qwen3.8-27B-Uncensored-FP8.
Use the Pi extension
Install dependencies and validate the package:
npm ci --ignore-scripts
npm run validate
Load the extension directly during development:
pi -e .
Or install this checkout as a persistent Pi package:
pi install /path/to/owo-local
Configure it interactively with /login owo-local, then enter:
- Base URL: your OpenAI-compatible server URL
- API key: your server API key, or leave it blank for a keyless server
- Model:
qwen3.8-27b-uncensored-fp8
For a shell that reads the existing secret without printing or copying it:
./scripts/owo-sglang-shell.sh
pi -e .
Available Pi commands:
/owo-local-statustests the connection and lists models./owo-local-refreshrefreshes the server model catalog./owo-local-helpshows setup instructions./owo-sglang-startstarts the user service and waits for model readiness./owo-sglang-stopstops the user service and frees both GPUs./owo-sglang-restartrestarts it and waits for readiness./owo-sglang-statusreports the systemd state and restart count./modelselects a discovered model.
Client configuration
The extension reads these optional environment variables:
| Variable | Purpose | Default |
|---|---|---|
OWO_LOCAL_URL |
OpenAI-compatible base URL | interactive setup |
OWO_LOCAL_API_KEY |
Bearer API key | keyless |
OWO_LOCAL_MODELS_URL |
Full or relative model-catalog URL | <base URL>/models |
OWO_LOCAL_HEADERS |
JSON object of additional request headers | none |
OWO_LOCAL_BEARER_AUTH |
Send Authorization: Bearer for the API key |
true |
OWO_LOCAL_MODEL(S) |
Offline fallback model IDs | none |
OWO_LOCAL_CONTEXT_WINDOW |
Context advertised to Pi | server value or 32K |
OWO_LOCAL_MAX_TOKENS |
Maximum generated tokens | server value or 4K |
OWO_LOCAL_REASONING |
auto, true, or false |
auto |
OWO_LOCAL_VISION |
auto, true, or false |
auto |
OWO_LOCAL_THINKING_FORMAT |
Provider thinking parameter format | Pi default |
OWO_LOCAL_DISCOVERY_TIMEOUT_MS |
/models request timeout |
5000 ms |
OWO_SGLANG_SERVICE |
User systemd unit controlled by Pi | qwen-sglang.service |
OWO_SGLANG_HEALTH_URL |
Readiness endpoint checked after start | local port 30000 |
OWO_SGLANG_START_TIMEOUT_MS |
Maximum model startup wait | 300000 ms |
Custom base paths are preserved. Full endpoint URLs such as
https://gateway.example/openai/v1/chat/completions are normalized to their
base URL automatically.
For a gateway with a separate catalog route and X-API-Key authentication:
export OWO_LOCAL_URL=https://gateway.example/openai/v1
export OWO_LOCAL_MODELS_URL=https://gateway.example/catalog/models
export OWO_LOCAL_API_KEY=your-secret
export OWO_LOCAL_BEARER_AUTH=false
export OWO_LOCAL_HEADERS='{"X-API-Key":"${OWO_LOCAL_API_KEY}","X-Tenant":"personal"}'
pi -e .
OWO_LOCAL_MODELS_URL may also be relative to the base URL. Model discovery
accepts OpenAI { "data": [...] }, { "models": [...] }, and raw array
responses. Entries may be model objects, { "model": "id" }, or ID strings.
SGLang deployment
This project serves orcarouter/Qwen3.8-27B-Uncensored-FP8 through SGLang's
OpenAI-compatible API. The included defaults target the following example
configuration:
- 2 x NVIDIA RTX 3090 (24 GiB each), tensor parallel 2
- 128K maximum context and 128K total token pool
- One active request for private, single-user serving
- FP8 KV cache, FP32 GDN/SSM state
- 2K chunked prefill for smoother decode latency
- Decode-only CUDA graphs to keep TP workers synchronized with asymmetric VRAM headroom
- Triton FP8 GEMM on Ampere, where native Hopper FP8 kernels are unavailable
- Text-only serving to avoid spending VRAM on the vision path
The checkpoint occupies about 31 GB on disk. With TP=2, the weights and runtime
state fit across the 48 GiB aggregate VRAM while retaining activation headroom.
The five-slot GDN cache is derived from SGLang's low-latency
extra_buffer strategy: 1 concurrent request x 5 state slots.
Install
Install the pinned environment:
./scripts/setup.shOpen the model page, accept its access terms, and create a read token.
Authenticate without putting the token in this repository:
.venv/bin/hf auth loginOptionally copy
.env.exampleto.envand change the bind address, port, API key, context, or concurrency.
Run
./scripts/serve.sh
The first run downloads the model into the normal Hugging Face cache. When the server reports that it is ready, test it from a second terminal:
./scripts/smoke-test.sh
The endpoint is http://127.0.0.1:30000/v1 by default. For an OpenAI client,
use qwen3.8-27b-uncensored-fp8 as the model name.
Terminal service control
Run SGLang in the background with the user systemd service:
systemctl --user start qwen-sglang
systemctl --user stop qwen-sglang
systemctl --user restart qwen-sglang
systemctl --user status qwen-sglang
Follow the server logs:
journalctl --user -u qwen-sglang -f
To run SGLang attached to the current terminal, stop the background service first and launch the server directly:
systemctl --user stop qwen-sglang
cd /path/to/owo-local
./scripts/serve.sh
Press Ctrl+C to stop a foreground server. Do not run the foreground command
while qwen-sglang.service is active because both processes will compete for
the GPUs and port 30000.
Reverse proxy or tunnel
To expose the server through a reverse proxy or tunnel, point it at
http://127.0.0.1:30000 and configure authentication at the server or proxy.
Keep credentials in environment variables or a local .env file that is not
committed to source control.
Tuning boundaries
The defaults target stable interactive use. The native model context is 262K, but that is not a sensible default on two 24 GiB cards. Keep these relationships when tuning:
- The Mamba cache size is derived automatically as
SGLANG_MAX_RUNNING_REQUESTS x 5for the low-latency strategy. - If increasing context, raise
SGLANG_MAX_TOTAL_TOKENSwith it and watch both GPUs during a worst-case prompt. Lower concurrency first if startup or prefill runs out of memory. - Keep 2K prefill chunks on these cards. Larger chunks increase peak activation memory and make active decoding less smooth.
- FP8 KV is intentional here. Switching to BF16 KV roughly doubles KV memory.
- Do not enable the bundled MTP head until the base profile is measured; it adds memory pressure and is not needed for a reliable first deployment.
Extra SGLang flags can be appended without editing the script:
./scripts/serve.sh --log-level debug
This configuration follows the upstream Qwen3.8-27B cookbook, with TP=2 and Ampere-compatible kernels substituted for the H200 recipe.