droid-model-setup
Skill128 starsChanged 5 months agoMITView on GitHub
Configure any third-party model as a custom model in Factory Droid (~/.factory/settings.json): resolve specs (context window, max output tokens, reasoning efforts), write a safe config entry, set session defaults, and prove the wiring with a live droid exec run and, when needed, an exact request-body capture. Fully open-ended: use whenever the user asks to "set X, Y, Z models up for a Droid", add/register a custom model, fix a model that ignores its reasoning setting, raise max tokens or context for BYOK models, or verify what parameters Droid actually sends. Triggers include "set up <model> for droid", "configure droid models", "add custom model", "which models does droid support", and "verify my droid model config".
In this repository5 other files it gives its agents.
- AGENTS.mdAGENTS.md
- windows-wip/AGENTS.mdAGENTS.md
- claude-apiSkill
- gpt-imageSkill
- grok-imagineSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 39
Set session defaults: if the user wants one of them as the daily driver (set-defaults subcommand sets model + matching reasoningEffort …
- Very specific: line 88
All fields observed in the binary's zod schema (optional unless noted): model* (upstream slug), id*, index* (unique int — script …
- Distinctive: line 100
Run a tiny dump server that records POST bodies to JSONL and returns a canned chat-completion response (a ~30-line Python http.server is …
- Very specific: line 107
Remove the temp entry (remove custom:dump-test) and kill the server.
- Very specific: line 132
Every mutating subcommand: timestamped backup next to the file, atomic-enough single write, post-write key-integrity assertion with …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Droid model setup
Turns any OpenAI-compatible (and most Anthropic-compatible) endpoint into a first-class Droid
model. Covers spec lookup, safe writes to ~/.factory/settings.json, session-default effort
wiring, and empirical verification. Knowledge below was verified Aug 2026 against the real binary
by capturing Droid's outgoing request bodies.
Workflow for "set X, Y, Z models up for a Droid"
- Resolve specs per model (ask only what cannot be looked up; be agentic otherwise).
- OpenRouter-hosted model: fetch
https://openrouter.ai/<vendor>/<slug>— gives context window, max completion tokens, supported reasoning efforts, pricing. - Other providers: check their docs/API reference for context length and output cap.
- Note whether thinking/reasoning can be toggled and via which parameter.
- OpenRouter-hosted model: fetch
- Determine endpoint + credentials.
- Same provider already registered in settings? Reuse its key with the script's
--reuse-key-from <existing-model-id>(reads the real stored bytes; the asterisks you see in file reads are display-only redaction, and Python sees through them). - New provider: ask the user for the base URL and API key if genuinely unknown. Defaults:
OpenRouter
https://openrouter.ai/api/v1, LM Studiohttp://127.0.0.1:1234/v1, llama.cpp/vLLM/Ollama-OpenAIhttp://127.0.0.1:<port>/v1. - Provider field:
generic-chat-completion-apicovers every OpenAI-compatible endpoint tested (OpenRouter, W&B, LM Studio, MTPLX).openaialso works for OpenAI-compat APIs.
- Same provider already registered in settings? Reuse its key with the script's
- Write entries with the helper script (never hand-edit settings.json — see gotchas).
Model
idin settings becomes the CLI-facing name:-m custom:<id>. - Set session defaults if the user wants one of them as the daily driver
(
set-defaultssubcommand sets model + matching reasoningEffort together). - Verify live, then report exactly what was configured and proven.
Hard rules
Never text-edit ~/.factory/settings.json. Existing apiKey values render as runs of
asterisks inside the agent's file viewer; a string-replacement edit that touches those lines
writes literal asterisks to disk and destroys real keys. Use scripts/droid_models.py, which
mutates parsed JSON (untouched values stay byte-identical), backs the file up first, and
afterward diffs every pre-existing key — restoring automatically and failing loudly if anything
changed. If you must edit manually anyway (new top-level keys etc.), anchor edits far away from
apiKey lines, then diff {id: len(apiKey)} old-vs-new via Python before declaring success.
Config is not verification. A written entry proves nothing. Always finish with:
droid exec -m custom:<model-id> 'Reply with exactly: config-ok'A successful run also re-proves the API key survived whatever edit preceded it.
How Droid actually sends requests (wire facts)
Captured exact body for a generic-chat-completion-api custom model:
{"model":"<slug>","stream":true,"max_tokens":<N>,"temperature":1,"reasoning_effort":"<effort>"}- Streaming is always on (
stream:trueis hardcoded, plusstream_options.include_usage); there is no settings knob and none needed. - No separate thinking object on this path:
reasoning_effortalone carries the intent; OpenRouter maps it toreasoning.effort. Anthropic-style paths instead getreasoning_effortverbatim plusbudget_tokens(low 4096, medium 12288, high/xhigh 24576, max = uncapped/0). maxOutputTokensmaps 1:1 tomax_tokens. Omit it and Droid falls back to small built-in ceilings — always set it to the model's real max completion tokens.- Effort ladder:
none, minimal, low, medium, high, xhigh, max, dynamic, off. - Resolution order beats model entry: exec
-r/--reasoning-effortflag >sessionDefaultSettings.reasoningEffort>customModels[].reasoningEffort. Classic bug: model entry saysmax, session default saysnone→ sessions run with thinking off. When configuring for real use, set BOTH (the script'sset-defaultsdoes this atomically). extraArgsis the escape hatch: arbitrary JSON merged last into every request body (wins over everything). Example:"extraArgs": {"top_p": 0.9}. No--streamstyle toggles — only body params.
full schema of a customModel entry
All fields observed in the binary's zod schema (optional unless noted):
model* (upstream slug), id, index (unique int — script auto-picks),
baseUrl, apiKey | apiKeyHelper(+apiKeyHelperTtlMs), authMode ("bearer" for Anthropic
SDK token path), provider*, displayName, maxContextLimit, maxOutputTokens,
enableThinking, thinkingMaxTokens, reasoningEffort, noImageSupport,
extraHeaders, extraArgs, bedrock, baseModelId.
Verification beyond config-ok
Token counts between efforts are NOT reliable proof of transmission (tiny prompts barely trigger thinking at any effort). To prove exact request bodies, do a wire capture:
- Run a tiny dump server that records POST bodies to JSONL and returns a canned chat-completion response (a ~30-line Python http.server is enough; return one fixed JSON body and log everything).
- Temporarily register a throwaway entry pointing at it
(
python3 scripts/droid_models.py add ... --base-url http://127.0.0.1:8899/v1 --api-key test-key). droid exec -m custom:dump-test -r max hi— exec fails on the fake response AFTER capture; ignore the failure, read/tmp/dump_requests.jsonl.- Remove the temp entry (
remove custom:dump-test) and kill the server.
Post-restart check: Droid has been observed keeping settings intact across restarts, but if a restart behaves oddly, simply Read settings.json again — if the entries are gone, they are gone; do not try to reconstruct state from caches or hack around it. Just re-run this skill's add commands (specs are cheap to re-fetch, keys come from wherever they're stored).
Helper script
# from your droidproxy checkout:
S=skills/droid-model-setup/scripts/droid_models.py
python3 $S list # registered custom models
python3 $S add z-ai/glm-5.3-flash \
--id GLM-5.3-Flash-0 --display-name "GLM 5.3 Flash" \
--base-url https://openrouter.ai/api/v1 \
--reuse-key-from custom:some-openrouter-model \
--effort max --max-context 1048576 --max-output 131072
python3 $S add <slug> --api-key sk-or-v1-... # explicit key instead
python3 $S add <slug> --extra-args '{"top_p":0.9}'
python3 $S set-defaults custom:GLM-5.3-Flash-0 --effort max # model+effort together
python3 $S remove custom:<id>Every mutating subcommand: timestamped backup next to the file, atomic-enough single write,
post-write key-integrity assertion with automatic restore on mismatch. Test safely against a
copy with --settings /tmp/settings-copy.json --no-exec-hint.
Reference implementation (GLM 5.3 Flash, Aug 2026)
Worked end-to-end: specs from OpenRouter page (1M context, 131072 max completion,
$0.075/$0.25 per M), entry added via safe mutation, both the model entry AND
sessionDefaultSettings set to effort max, then verified three ways: config-ok exec run,
key-integrity post-check, and wire capture showing reasoning_effort:"max" +
max_tokens:131072 + stream:true in the actual outgoing body.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

