A small F# localhost harness for inspecting OpenAI-compatible chat requests and fulfilling them through a manual JSON buffer. The same process accepts typed, read-only observations from browser and desktop perception producers.
This project is a fun take on a model server. It preserves incoming chat JSON, exposes pending requests, and waits for a deliberate response at /v1/buffer.
Dependencies:
- Tasket Communication Daemon at CommanderTurtle/macrohelp : Macro HTTPD
- Dangerously greppable markdown files at CommanderTurtle/regedited : Zone'd ripgrep sorted by index
flowchart LR
Client["OpenAI-compatible client"] --> Chat["F# chat and buffer daemon"]
Chat --> Files["Atomic latest-state files and JSONL history"]
Buffer["Human or local response tool"] --> Chat
DOM["Surfingkeys DOM producer"] --> Vision["Typed observation endpoint"]
Desktop["Optional Python UIA / OCR / CV"] --> Vision
Vision --> Files
The daemon is the transport boundary. Vision producers cannot click, type, or execute actions.
- .NET 10 SDK
uvand Python 3.12+ foroptional_vision- Bun only when checking the Surfingkeys integration
- Optional native Tesseract executable for OCR
git clone <repository-url>
cd openai-buffer-daemon
./scripts/Build.ps1
./scripts/Start.ps1The default base URL is http://127.0.0.1:5087. Runtime files default to the current user's Desktop; set a different location with -DataDirectory.
./scripts/Start.ps1 -Url http://127.0.0.1:5091 -DataDirectory "$env:TEMP/openai-buffer-daemon"Start a waiting request in one terminal:
$body = @{ model = 'manual-buffer-model'; messages = @(@{ role = 'user'; content = 'Hello' }) } | ConvertTo-Json -Depth 20
Invoke-RestMethod http://127.0.0.1:5087/v1/chat/completions -Method Post -ContentType application/json -Body $bodyFulfill it from another terminal:
Invoke-RestMethod http://127.0.0.1:5087/v1/buffer -Method Post -ContentType application/json -Body '{"content":"Hello from the buffer."}'/v1/buffer may receive a simple content value or a complete response containing choices. A request_id targets a particular pending request; otherwise the oldest pending request is completed.
| Method | Path | Behavior |
|---|---|---|
GET |
/health |
Process and queue health |
GET |
/v1/models |
Local compatibility model |
POST |
/v1/chat/completions |
Wait for a buffer response; SSE supported |
GET/POST |
/v1/buffer |
Inspect or fulfill the pending queue |
GET |
/v1/pending |
Pending request metadata |
GET |
/v1/requests/latest |
Latest untouched request |
GET |
/v1/vision/schema |
Bundled observation schema |
GET/POST |
/v1/vision/observations |
Observation status or ingestion |
GET |
/v1/vision/observations/latest |
Latest accepted observation |
POST |
/v1/macro |
Replace the persistent Tasket .scht pointer or set it to off |
POST |
/v1/rgd1 ... /v1/rgd5 |
Replace one persistent Regedited command slot |
POST |
/v1/zuko |
Convert submitted text into %TEMP%\tempreg.txt, then optionally call Tasket |
POST |
/v1/iroh |
Run one Regedited slot, wrap the clipboard, then optionally call Tasket |
Other common /v1 POST routes are logged compatibility stubs and return 501; the daemon does not falsely claim those capabilities.
uv sync --project optional_vision --extra all --group dev
uv run --project optional_vision buffer-vision doctor
uv run --project optional_vision buffer-vision observe --cv --output observation.json --overlay observation.png
uv run --project optional_vision buffer-vision observe --cv --postThe preference order is DOM, UI Automation, OCR, then generic CV geometry. See optional_vision/README.md and docs/ARCHITECTURE.md.
./scripts/Test-All.ps1This builds F#, runs Python unit and schema tests, and proves the chat/buffer and observation handshakes against a temporary live daemon.
These routes share one replaceable Regedited output file:
%TEMP%\tempreg.txt
Every Zuko or Iroh call creates a blank canonical one-index Regedited document, then pipes the submitted or captured multiline text through rgd rs as i1z1. Regedited owns the final zone range and any relocation bookkeeping. The resulting text is available as:
rgd load $env:TEMP\tempreg.txt
rgd rg i1z1 --clipSet the Tasket macro pointer with a literal filename. Posting another filename replaces it persistently:
Invoke-RestMethod 'http://127.0.0.1:5087/v1/macro' -Method Post -ContentType 'text/plain' -Body 'something.scht'After Zuko or Iroh writes tempreg.txt, the daemon posts this saved filename to Tasket at http://127.0.0.1:7777/run.
To generate tempreg.txt without invoking Tasket, persist the literal value off:
Invoke-RestMethod 'http://127.0.0.1:5087/v1/macro' -Method Post -ContentType 'text/plain' -Body 'off'off affects only the final Tasket dispatch. Zuko and Iroh still create the template, populate it through rgd rs, and replace %TEMP%\tempreg.txt.
Send plain multiline Markdown to Zuko:
$text = @'
# Work item
Keep this multiline body exactly as written.
'@
Invoke-RestMethod 'http://127.0.0.1:5087/v1/zuko' -Method Post -ContentType 'text/plain' -Body $textZuko preserves the multiline Markdown apart from newline normalization. A JSON string or a JSON object containing content, text, or markdown is accepted as well.
Each numbered endpoint persistently stores one literal shell command beginning with rgd:
Invoke-RestMethod 'http://127.0.0.1:5087/v1/rgd1' -Method Post -ContentType 'text/plain' -Body 'rgd rg C:\path\to\registry.txt i4z2 --clip'Use /v1/rgd2, /v1/rgd3, /v1/rgd4, and /v1/rgd5 identically. Posting a new command to a slot replaces only that slot. Commands may use any native Regedited operation, but the stored text must begin with rgd.
Posting its number to Iroh runs that saved command, reads the current clipboard, replaces %TEMP%\tempreg.txt with the clipboard as i1z1, and invokes the macro currently designated by /v1/macro:
Invoke-RestMethod 'http://127.0.0.1:5087/v1/iroh' -Method Post -ContentType 'text/plain' -Body '1'Iroh accepts only the literal selector 1, 2, 3, 4, or 5. The selected command is run first; the clipboard content present afterward becomes the complete i1z1 payload. With /v1/macro set to off, the same file is produced and Tasket is skipped.
If the chat request contains "stream": true, the daemon returns an SSE stream. While waiting, it emits SSE comments like : thinking 2026-... so compatible clients keep the connection alive without receiving fake assistant text. When /v1/buffer receives the response, the daemon sends the final content chunk and data: [DONE].
The configurable, independently installable MCP template lives in optional-mcp. It can submit larger-model requests through Zuko, observe configured Regedited results, and recover the last temporary payload without becoming part of the daemon process.
- The daemon binds to
127.0.0.1by default and requires no API key. - Unsupported
/v1/*POST endpoints are logged and return a structured501JSON body. - Multimodal Chat Completions bodies are preserved exactly, including
image_urlcontent parts. - Vision producers remain separate from the daemon. See integrations/surfingkeys for the DOM producer and contracts/vision-observation.schema.json for the observation contract.
- The older
PiProxyVLLMproxy is reference material only; it is intentionally not bundled into this daemon.
AGPL-3.0-only. See LICENSE.
