Jack is a local MLX skill-adapter runtime for Apple Silicon. It binds one exact
Qwen/Qwen3-8B-MLX-4bit revision to code-free, independently versioned
MLX-LM LoRA bundles, then routes each request to either the base or exactly one
installed adapter.
Jack owns the local Unix-socket protocol, base verification, bundle inspection, registry, routing, bounded adapter cache, cancellation, and evidence. OptiQ 0.4.2 is the currently selected live mounted-LoRA backend; the exact unpatched MOLA revision is retained as an independently qualified alternative.
The repository contains no trained skill adapter, training pipeline, downloaded dataset, or autoresearch execution path.
Requirements are macOS on Apple Silicon, Python 3.12 or 3.13, uv, and bd.
uv sync --all-groups
uv lock --check
uv build--all-groups includes the pinned qualification candidates. Normal Jack imports
remain lazy and do not import either candidate server.
uv run pytest -q
git diff --check
uv run python -m compileall -q src testsHardware-gated checks use already verified local material:
JACK_LIVE_HOME="$PWD/.jack" uv run pytest \
tests/integration/test_optiq_conformance.py \
tests/integration/test_mola_conformance.py \
-q -m integrationGateway contract and live-route checks are:
uv run pytest tests/gateway tests/integration/test_openai_client.py \
tests/integration/test_gateway_clients.py -q
JACK_GATEWAY_LIVE_HOME="$PWD/.jack" uv run pytest \
tests/integration/test_gateway_live.py -q -m integrationThe live gateway check requires a running daemon, the verified exact base, a selected accepted backend, and at least one installed exact adapter.
Inspect first. Acquisition is the only command allowed to fetch the pinned revision and always requires explicit confirmation.
uv run jack base inspect --json
uv run jack base acquire --yes --json
uv run jack base verify --jsonRuntime startup and generation operate offline and never download missing material.
uv run jack backend qualify --candidate optiq \
--base-lock config/base.lock.json --json
uv run jack backend qualify --candidate mola \
--base-lock config/base.lock.json --json
uv run jack backend list --json
uv run jack backend select --candidate optiq --jsonSelection accepts only complete evidence for the current clean repository revision, base lock, dependency set, and candidate profile.
Jack permits one cooperating model workload per macOS user, even when
processes use different JACK_HOME or campaign roots. Live daemon generation,
base probing, and backend qualification join this authority automatically.
The daemon retains its lease while a live model is resident, including idle
time, and releases it only after model cleanup.
Start an authorised campaign, training job, or model evaluation as one foreground process:
uv run jack workload run --kind campaign \
--owner applescript-pilot -- <foreground-command>Use training or model-evaluation for the other supported workload kinds.
The command must remain in the foreground; daemonising is unsupported because
the inherited descriptor defines the lease lifetime.
A contender exits safely with resource.model_workload_busy before model,
route, adapter, report, or command mutation. Stop the cooperating owner
normally, or let it exit, then retry. Do not delete the persistent lock file,
probe PIDs, or signal a process based on diagnostic metadata.
The lease does not block fake generation, daemon status, registry inspection,
documentation or dataset/source research, or AppleScript source compilation
that performs no model work. Pre-existing direct MLX and legacy autoresearch
processes are outside Jack's authority: Jack neither detects nor signals them.
Do not disturb such a process; migrate its next run to jack workload run.
Set JACK_HOME when managed state should live somewhere other than
$PWD/.jack.
uv run jack daemon start --detach
uv run jack status --json
uv run jack adapter validate /path/to/bundle --json
uv run jack adapter install /path/to/bundle --json
uv run jack adapter list --json
uv run jack runtime inspect --json
uv run jack daemon stopInstalled adapter identities are name@version:
uv run jack generate --prompt "Hello" --json
uv run jack generate --prompt "Hello" \
--adapter example@1.0.0 --jsonThe optional gateway is a separate loopback-only process. Start the Jack daemon first, then start the gateway and display its one local bearer token:
uv run jack daemon start --detach
uv run jack gateway start --detach --port 8080
uv run jack gateway token show
uv run jack gateway status --jsonUse http://127.0.0.1:8080/v1 as the OpenAI base URL and the displayed token as
the API key. Public model names are exact: jack/base selects no adapter, while
jack/<name>@<version> selects exactly one installed adapter. GET /v1/models
lists only the verified base and installed adapters reported by the daemon.
There are no aliases, paths, latest resolution, multi-adapter routes, or
silent base fallback.
Revision 1 supports POST /v1/chat/completions with model, plain-string
system/user/assistant messages, stream, max_tokens, temperature, and
response_format of text or non-streaming json_object. Other OpenAI fields
fail explicitly instead of being ignored. Text responses and SSE streams work
with OpenAI Python 2.51.0:
from openai import OpenAI
client = OpenAI(
base_url="http://127.0.0.1:8080/v1",
api_key="<output of jack gateway token show>",
)
reply = client.chat.completions.create(
model="jack/base",
messages=[{"role": "user", "content": "Hello"}],
)Hermes Agent can use the same base URL, token, and exact model ID for an
auxiliary OpenAI chat model. Honcho can use
response_format={"type": "json_object"} as a transport option. That Honcho
fixture proves only HTTP and JSON-object compatibility: it does not prove
that Jack's memory-extraction output matches Honcho's memory schema, and it does
not make the in-flight memory adapter operationally ready.
Ordinary text generation keeps Qwen thinking enabled by default. JSON-object
mode adds one fixed instruction and disables thinking for that request at
Jack's shared renderer, then accepts only one complete JSON object. It does not
repair malformed output, extract fenced JSON, strip thinking tags, retry, use a
fallback model, or implement json_schema or tools.
The token is stored at .jack/secrets/openai.token with mode 0600; the
directory is mode 0700. The gateway listens only on 127.0.0.1, logs no
prompts, completions, tokens, or authorisation headers, and is intended for
same-user local clients—not hostile local-user isolation.
If the daemon stops, authenticated health becomes degraded and daemon-dependent
requests return service_unavailable; restart the daemon and retry. Correct an
exact model name when model_not_found is returned. Stop or rotate the local
gateway with:
uv run jack gateway stop
uv run jack gateway token rotateFrom a clean checkout with the verified base and a current accepted backend:
uv run jack daemon start --detach
uv run jack verify core --json
uv run jack daemon stopThe command runs the protocol/bundle, registry, and routing recovery gates;
validates the base and selected live-backend evidence; audits later-scope paths;
and writes an immutable CORE-EVIDENCE-V1 report under
.jack/reports/core/verification/. Any dirty, stale, missing, blocked, failed,
or untested evidence returns non-zero and cannot be promoted to ready.
Project contracts, design, research, and the implementation graph are indexed
in docs/README.md. Work is tracked with Beads; run bd prime
before changing the project.